gpt4 book ai didi

java - 尝试从波前.obj文件加载纹理时,为什么在使用索引渲染(glDrawElements)时纹理显示不正确?

转载 作者:行者123 更新时间:2023-11-30 02:08:21 25 4
gpt4 key购买 nike

介绍

我正在构建一个简单的wavefront .obj文件解析器。我设法使其读取文件,存储了文件的内容(顶点位置,顶点坐标,顶点法线(尚未使用)和多边形面元素信息(例如5/2/3))。然后将此数据传递到一个类(称为GameEntity),并从那里开始使用GL_TRIANGLES模式下的glDrawElements将数据用于将该特定实体(在这种情况下为立方体)呈现到呈现循环内的屏幕。但是,纹理渲染不正确。

源代码

OBJLoader.java

public class OBJLoader {    
/**
* This method loads a model represented by a wavefront .obj file from resources/models using
* the specified name of the file (without the .obj extension) and a full path to the texture used
* by the model. It passes the information (vertex positions, texture coordinates, indices)
* obtained from the .obj file to the GameEntity constructor.
* @param fileName
* @param texturePath
* @return
* @throws Exception
*/
public static GameEntity loadObjModel(String fileName, String texturePath) throws Exception {
double start = System.nanoTime();

List<Vector3f> vertices = null;
List<Vector2f> textures = null;
List<Vector3f> normals = null;
List<Integer> indices = null;

String line;

float[] vertexPosArray = null;
float[] texturesArray = null;
float[] normalsArray = null;
int[] indicesArray = null;

try {
FileReader fr = new FileReader(new File("resources/models/" + fileName + ".obj"));
BufferedReader br = new BufferedReader(fr);
vertices = new ArrayList<>();
textures = new ArrayList<>();
normals = new ArrayList<>();
indices = new ArrayList<>();

while((line = br.readLine()) != null) {

if (!line.equals("") || !line.startsWith("#")) {
String[] splitLine = line.split(" ");

switch(splitLine[0]) {
case "v":
Vector3f vertex = new Vector3f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]), Float.parseFloat(splitLine[3]));
vertices.add(vertex);
System.out.println("[OBJLoader.loadObjModel]: Vertex " + vertex.toString() + " has been added to vertices from " + fileName);
break;
case "vt":
Vector2f texture = new Vector2f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]));
textures.add(texture);
System.out.println("[OBJLoader.loadObjModel]: Texture coordinate [" + texture.x + ", " + texture.y + "] has been added to textures from " + fileName);
break;
case "vn":
Vector3f normal = new Vector3f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]), Float.parseFloat(splitLine[3]));
normals.add(normal);
System.out.println("[OBJLoader.loadObjModel]: Normal " + normal + " has been added to normals from " + fileName);
break;
}
}
}

int numVertices = vertices.size();
System.out.println("[OBJLoader.loadObjModel]: numVertices = " + numVertices);
texturesArray = new float[numVertices*2];
System.out.println("[OBJLoader.loadObjModel]: length of texturesArray = " + texturesArray.length);
normalsArray = new float[numVertices*3];

br.close(); //find a better way to start a file again
br = new BufferedReader(new FileReader("resources/models/" + fileName + ".obj"));

while((line = br.readLine()) != null) {
if (line.startsWith("f")) {
System.out.println(" [OBJLoader.loadObjModel]: Found line starting with f!");
String[] splitLine = line.split(" ");

//f should be omitted, therefore not starting at index 0
String[] v1 = splitLine[1].split("/");
String[] v2 = splitLine[2].split("/");
String[] v3 = splitLine[3].split("/");

System.out.println(" v1 | " + v1[0] + ", " + v1[1] + ", " + v1[2]);
System.out.println(" v2 | " + v2[0] + ", " + v2[1] + ", " + v2[2]);
System.out.println(" v3 | " + v3[0] + ", " + v3[1] + ", " + v3[2]);

processVertex(v1, indices, textures, normals, texturesArray, normalsArray);
processVertex(v2, indices, textures, normals, texturesArray, normalsArray);
processVertex(v3, indices, textures, normals, texturesArray, normalsArray);
}
}
br.close();

} catch (Exception e) {
System.err.println("[OBJLoader.loadObjModel]: Error loading obj model!");
e.printStackTrace();
}

vertexPosArray = new float[vertices.size()*3];
indicesArray = new int[indices.size()];

int i = 0;
for(Vector3f vertex : vertices) {
vertexPosArray[i++] = vertex.x;
vertexPosArray[i++] = vertex.y;
vertexPosArray[i++] = vertex.z;
}

for(int j = 0; j<indices.size(); j++) {
indicesArray[j] = indices.get(j);
}

double end = System.nanoTime();
double delta = (end - start) / 1000_000;
System.out.println("[OBJLoader.loadObjModel]: Vertices array of " + fileName + ": ");
System.out.println("[OBJLoader.loadObjModel]: It took " + delta + " milliseconds to load " + fileName);

System.out.println("[OBJLoader.loadObjModel]: Ordered vertex position array: " + ArrayUtils.getFloatArray(vertexPosArray));
System.out.println("[OBJLoader.loadObjModel]: Ordererd texture coordinates array: " + ArrayUtils.getFloatArray(texturesArray));
System.out.println("[OBJLoader.loadObjModel]: Ordererd indices array: " + ArrayUtils.getIntArray(indicesArray));

return new GameEntity(vertexPosArray, indicesArray, texturesArray, texturePath);
}

/**
* The input to this method is vertex data as a String array, which is used to determine how to
* arrange texture coordinate and normal vector data (this data is associated with each vertex position)
* into the correct order in the texture and normals array
* @param vertexData
* @param indices
* @param textrues
* @param normals
* @param textureArray
* @param normalsArray
*/
private static void processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures,
List<Vector3f> normals, float[] textureArray, float[] normalsArray) {
int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
System.out.println("[OBJLoader.processVertex]: currentVertexPointer = " + currentVertexPointer);
indices.add(currentVertexPointer);
System.out.println("[OBJLoader.processVertex]: Adding " + currentVertexPointer + " to indices!");

Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
textureArray[currentVertexPointer*2] = currentTex.x;
textureArray[currentVertexPointer*2 + 1] = 1.0f - currentTex.y;
System.out.println("[OBJLoader.processVertex]: Added vt " + currentTex.x + " to index " + currentVertexPointer*2 +
" and vt " + (1.0f - currentTex.y) + " to index " + (currentVertexPointer*2+1) + " of the textureArray");

Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2]) - 1);
normalsArray[currentVertexPointer*3] = currentNorm.x;
normalsArray[currentVertexPointer*3 + 1] = currentNorm.y;
normalsArray[currentVertexPointer*3 + 2] = currentNorm.z;
}
}


GameEntity构造函数:

    /**
* Creates a new textured GameEntity
* @param vPositions The vertex coordinates of a model
* @param indices The indices of a model (in which order should the vertices be bound by OpenGL?)
* @param textureCoordinates The coordinates of a texture (which texture coordinate should be applied to which vertex?)
* @param texturePath The path of the texture
* @throws Exception
*/
public GameEntity(float[] vPositions, int[] indices, float[] textureCoordinates, String texturePath) throws Exception{
System.out.println("[GameEntity.GameEntity]: Creating a new model texture...");
modelTexture = new Texture(texturePath);
System.out.println("[GameEntity.GameEntity]: Creating new mesh based on parameters... ");
mesh = new Mesh(vPositions, indices, textureCoordinates, modelTexture);

System.out.println("[GameEntity.GameEntity]: Initializing position, scale and rotation instance fields... ");
position = new Vector3f(0, 0, 0);
scale = 1;
rotation = new Vector3f(0, 0, 0);
}


仅注意将顶点位置,索引和纹理坐标(以及创建的纹理)发送到Mesh构造函数这一事实:

网格构造器

/**
* This constructor creates a renderable object (instance of Mesh with its texture) out of input parameters by storing them
* in the vao of that Mesh instance
* @param vertices The vertex positions of a model
* @param indices The indices to tell OpenGL how to connect the vertices
* @param texCoords Texture coordinates (used for texture mapping)
* @param texture A Texture object
*/
public Mesh(float[] vertices, int[] indices, float[] texCoords, renderEngine.Texture texture) {
System.out.println("[Mesh.Mesh]: Creating a new textured Mesh instance... ");

verticesBuffer = null;
textureBuffer = null;
indicesBuffer = null;

try {
this.texture = texture;
vertexCount = indices.length;

vbos = new ArrayList<>();
vaos = new ArrayList<>();
textures = new ArrayList<>();

System.out.println("[Mesh] Creating and binding the vao (vaoID)");
vaoID = glGenVertexArrays();
vaos.add(vaoID);
glBindVertexArray(vaoID);

setupVerticesVbo(vertices);

setupIndicesBuffer(indices);

setupTextureVbo(texCoords);

textures.add(texture);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}


Mesh类的相关方法是 setupIndicesBuffersetupTextureVbo

    private void setupIndicesBuffer(int[] indices)  {
indicesVboID = glGenBuffers();
vbos.add(indicesVboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVboID);
indicesBuffer = BufferUtilities.storeDataInIntBuffer(indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
}

/**
* This method sets up the texture vbo for a mesh object (buffers data to it and assigns it to attribute list
* index 1 of the vao)
*
* @param colours - an array of colours of the vertices of a model
*/
private void setupTextureVbo(float[] textures) {
System.out.println("[Mesh] Creating texture vbo (textureVboID)...");
textureVboID = glGenBuffers();
vbos.add(textureVboID);

System.out.println(" - [Mesh] Creating texture buffer (textureBuffer)...");
textureBuffer = BufferUtilities.storeDataInFloatBuffer(textures);

System.out.println(" - [Mesh] Binding textureVboID to GL_ARRAY_BUFER...");
glBindBuffer(GL_ARRAY_BUFFER, textureVboID);

System.out.println(" - [Mesh] Buffering data from textureBuffer to GL_ARRAY_BUFFER...");
glBufferData(GL_ARRAY_BUFFER, textureBuffer, GL_STATIC_DRAW);

System.out.println(" - [Mesh] Sending texture vbo to index 1 of the active vao...");
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
}


cube.obj

# Blender v2.78 (sub 0) OBJ File: 'cube.blend'
# www.blender.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.2766 0.2633
vt 0.5000 0.4867
vt 0.2766 0.4867
vt 0.7234 0.4867
vt 0.9467 0.2633
vt 0.9467 0.4867
vt 0.0533 0.4867
vt 0.0533 0.2633
vt 0.2766 0.0400
vt 0.5000 0.2633
vt 0.0533 0.7100
vt 0.7234 0.2633
vt 0.0533 0.0400
vt 0.2766 0.7100
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
s off
f 2/1/1 4/2/1 1/3/1
f 8/4/2 6/5/2 5/6/2
f 5/7/3 2/1/3 1/3/3
f 6/8/4 3/9/4 2/1/4
f 3/10/5 8/4/5 4/2/5
f 1/3/6 8/11/6 5/7/6
f 2/1/1 3/10/1 4/2/1
f 8/4/2 7/12/2 6/5/2
f 5/7/3 6/8/3 2/1/3
f 6/8/4 7/13/4 3/9/4
f 3/10/5 7/12/5 8/4/5
f 1/3/6 4/14/6 8/11/6


我所取得的成就


观看 视频
查看GitHub上的 this页面以获取OBJLoader的解释
查看源代码的 this存储库(尚未包括OBJLoader,但是您可以查看其他类,例如GameEntity或Mesh,因为这两个类是顶点数据被发送到之后的类。从.obj文件中提取)。


该视频首先显示OBJLoader类的源代码。然后,它显示如何错误地映射多维数据集上的纹理(多维数据集的背面和左侧除外)。然后,它显示了一个文件,在该文件中我分析了保存纹理坐标信息的数组中的每个索引被写入多少次。最后,显示了应映射的纹理。

问题

如视频所示,立方体的六个面中有四个不正确地映射了纹理。

我确实知道:
  -可以从.obj文件正确读取纹理坐标,并将其存储在纹理ArrayList中。可以在switch子句中找到此代码:

case "vt":
Vector2f texture = new Vector2f(Float.parseFloat(splitLine[1]), Float.parseFloat(splitLine[2]));
textures.add(texture);
break;


我确定50/50:
  -从.obj文件正确确定了索引,因为如果没有正确确定索引,则根本不会绘制多维数据集。与此相关的代码可以在processVertex方法中找到:

int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
indices.add(currentVertexPointer);


我不确定是否:
  -纹理在最终的float数组中正确排序,该数组称为texturesArray。与该步骤相关的代码可以在processVertex方法中找到:

Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
textureArray[currentVertexPointer*2] = currentTex.x;
textureArray[currentVertexPointer*2 + 1] = 1.0f - currentTex.y;


它应该如何工作:

首先,要从.obj文件中读取纹理坐标,并将其作为Vector2f(二维矢量,基本上只是存储x和y值)存储在名为纹理的ArrayList中。

但是,为了使OpenGL正常工作,应重新排列这些纹理坐标,以使其与相应的顶点匹配(至少这是我从多个教程中学到的方法)。这是通过阅读所谓的多边形面元素来完成的。

这些多边形面元素以每行以 f开头来描述。每条这样的线描述三个顶点。每个顶点由顶点位置,纹理坐标和法线向量表示。这样的行的示例: f 8/4/2 6/5/2 5/6/2。仔细查看 8/4/2顶点表示。这表明该顶点的位置等于.obj文件中的第八个指定顶点位置( -1.000000 1.000000 -1.000000),纹理坐标等于文件中的第四个指定纹理坐标( 0.7234 0.4867)和第二法向矢量(0.0000 1.0000 0.0000 )。

找到以f开头的线时,每次调用processVertex方法三次,以处理描述该多边形面元素的每个顶点(一次用于 8/4/2,一次用于 6/5/2,一次对于 5/6/2)。每次,一组数据作为String数组(在正斜杠的位置分割)传递给该方法,然后是List纹理,List法线,float [] textureArray和float [] normalsArray。

private static void processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures,
List<Vector3f> normals, float[] textureArray, float[] normalsArray) {
int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
System.out.println("[OBJLoader.processVertex]: currentVertexPointer = " + currentVertexPointer);
indices.add(currentVertexPointer);
System.out.println("[OBJLoader.processVertex]: Adding " + currentVertexPointer + " to indices!");

//something probably wrong here
Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
textureArray[currentVertexPointer*2] = currentTex.x;
textureArray[currentVertexPointer*2 + 1] = 1.0f - currentTex.y;
System.out.println("[OBJLoader.processVertex]: Added vt " + currentTex.x + " to index " + currentVertexPointer*2 +
" and vt " + (1.0f - currentTex.y) + " to index " + (currentVertexPointer*2+1) + " of the textureArray");

Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2]) - 1);
normalsArray[currentVertexPointer*3] = currentNorm.x;
normalsArray[currentVertexPointer*3 + 1] = currentNorm.y;
normalsArray[currentVertexPointer*3 + 2] = currentNorm.z;
}


注意,顶点普通数据是无关紧要的,因此可以忽略。

首先通过将所传递的String数组中的第一个数字减去一个数字来确定当前顶点索引(例如,如果 8/4/2作为参数传递,则将7分配给currentVertexPointer)。减去一个的原因是wavefront .obj文件中的图像从1开始,而Java中的索引从0开始。然后,将此数字添加到索引List中。

然后,通过读取作为参数传递的String数组中的第二个数字并减去一个数字(例如,如果 8/4/2作为参数传递,则Vector3f),从纹理列表中获取相应的纹理坐标(表示为Vector2f)。将获得纹理列表的索引3): Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);

现在,已获取到当前正在处理的顶点的对应纹理坐标(由currentVertexPointer表示),现在必须将数据相应地存储在textureArray中,然后将其传递给GameEntity以构造可渲染对象(有关此细节,将不再赘述)。讨论...底线:此数组中的顺序很重要,因为它会影响纹理映射到模型的方式)。

为了相应地存储纹理坐标,第一个纹理坐标(在某些情况下称为u或s)存储在textureArray的索引处,该索引的大小是currentVertexPointer的两倍,因为每个顶点都有两个纹理坐标: textureArray[currentVertexPointer*2] = currentTex.x;。第二个纹理坐标(某些情况下为v或t)存储在textureArray的索引处,该索引比第一个纹理坐标的索引大: textureArray[currentVertexPointer*2 + 1] = 1.0f - currentTex.y;

请注意,由于波前文件和OpenGL的纹理坐标空间不同,第二个纹理坐标从1.0f中减去。

我的观察

每当将新纹理分配给textureArray中的新(或现有)索引时,我都进行了跟踪,发现某些索引被覆盖了,这可能是造成问题的原因

在分析数据之后,我得到了这样的文件,该文件在右侧的textureArray中显示填充的索引,以及在执行期间分配给这些索引的各种元素:

 Index | values that get assigned to the index during execution of the program
0 | 0.2766 ... 0.2766 (third f-call) ... 0.2766 (sixth f-call) ... 0.2766 (14th f-call)
1 | 0.5133 ... 0.5133 (third f-call) ... 0.5133 (sixth f-call) ... 0.5133 (14th f-call)
2 | 0.2766 ... 0.2766 (third f-call) ... 0.2766 (fourth f-call) ... 0.2766 (seventh f-call) ... 0.2766 (ninth f-call)
3 | 0.7367 ... 0.7367 (third f-call) ... 0.7367 (fourth f-call) ... 0.7367 (seventh f-call) ... 0.7367 (ninth f-call)
4 | 0.2766 ... 0.5 (fifth f-call) ... 0.5 (seventh f-call) ... 0.2766 (twelveth f-call) ... 0.5 (13th f-call)
5 | 0.96 ... 0.7367 (fifth f-call) ... 0.7367 (seventh f-call) ... 0.96 (twelveth f-call) ... 0.7367 (13th f-call)
6 | 0.5 ... 0.5 (fifth f-call) ... 0.5 (seventh f-call) ... 0.2766 (14th f-call)
7 | 0.5133 ... 0.5133 (fifth f-call) ... 0.5133 (seventh f-call) ... 0.29000002 (14th f-call)
8 | 0.9467 ... 0.0533 (third f-call) ... 0.0533 (sixth f-call) ... 0.0533 (ninth f-call)
9 | 0.5133 ... 0.5133 (third f-call) ... 0.5133 (sixth f-call) ... 0.5133 (ninth f-call)
10 | 0.9467 ... 0.0533 (fourth f-call) ... 0.9467 (eighth f-call) ... 0.0533 (ninth f-call) ... 0.0533 (twelveth f-call)
11 | 0.7367 ... 0.7367 (fourth f-call) ... 0.7367 (eighth f-call) ... 0.7367 (ninth f-call) ... 0.7367 (twelveth f-call)
12 | 0.7234 ... 0.0533 (twelveth f-call) ... 0.7234 (13th f-call)
13 | 0.7367 ... 0.96 (twelveth f-call) ... 0.7367 (13th f-call)
14 | 0.7234 ... 0.7234 (fifth f-call) ... 0.0533 (sixth f-call) ... 0.7234 (eighth f-call) ... 0.7234 (13th f-call) ... 0.0533 (14th f-call)
15 | 0.5133 ... 0.5133 (fifth f-call) ... 0.29000002 (sixth f-call) ... 0.5133 (eighth f-call) ... 0.5133 (13th f-call) ... 0.29000002 (14th f-call)

All of the indexes in the texturesArray have been accessed and assigned values several time.

Indexes with unchanged values (ie, indexes which have been assigned the same value every time):
0, 1, 2, 3, 9, 11

Indexes with changed value (ie, indexes which have been assigned different values):
4, 5, 6, 7, 8, 10, 12, 13, 14


显然,大多数索引被不同的纹理坐标数据覆盖。用相同的纹理坐标数据覆盖的索引是0、1、2、3、9和11。因此,我推测由于这些索引被相同的值覆盖,因此背面和左侧的映射正确。而其他索引将被不同的值覆盖。

如何解决该问题?

呵呵,事实证明这很长,不是吗?谢谢您所花的所有时间,非常感谢。

编辑#1

在@florentt的第一个回答之后,我已经完成了将以下代码集成到processVertex方法中的工作:

    private static void processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures,
List<Vector3f> normals, float[] textureArray, float[] normalsArray) {

int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
System.out.println("[OBJLoader.processVertex]: currentVertexPointer = " + currentVertexPointer);
indices.add(currentVertexPointer);

//THIS IS NEW
Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
if ((textureArray[currentVertexPointer*2] + textureArray[currentVertexPointer*2+1])== 0 ) { //if the index hasn't been populated yet, store it
textureArray[currentVertexPointer*2] = currentTex.x;
textureArray[currentVertexPointer*2+1] = 1.0f - currentTex.y;
} else {
//create a new vertex (index?) and associate it with second coordinate u
//create a new vertex (index?) and associate it with texture coordinate v
}
//END OF NEW CODE

Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2]) - 1);
normalsArray[currentVertexPointer*3] = currentNorm.x;
normalsArray[currentVertexPointer*3 + 1] = currentNorm.y;
normalsArray[currentVertexPointer*3 + 2] = currentNorm.z;
}


他报告说,此问题是由于一个顶点与几个不同的顶点坐标(属于不同的面)相关联而引起的。每个这样的顶点都应该复制并分配一个相应的纹理坐标。我在processVertex方法中添加了if子句,该子句检查特定纹理坐标集的索引是否在texturesArray中为空。如果float数组中的索引为空,则其值为0。要计算此索引和连续索引是否为空(每个顶点具有两个纹理坐标),则这些索引处的值之和必须为0。都是空的。如果这两个索引尚未填充纹理坐标,则为它们分配可以从当前正在处理的多边形面元素(即 8/4/2)获得的纹理坐标。

但是,当索引已被填充时,我没有丝毫线索。我知道位置矢量应该被复制并分配相应的纹理坐标(以与上述相同的方式访问),但是这不会改变从.obj文件读取的原始位置矢量的整个ArrayList吗?在 processVertex(String[] vertexData, List<Integer> indices, List<Vector2f> textures, List<Vector3f> normals, float[] textureArray, float[] normalsArray)方法的情况下,这些重复的矢量应存储在哪里?您是否应该只复制此位置向量的索引,然后为该索引分配纹理坐标?然后应该如何将纹理坐标存储到这一新索引?

我的第一个尝试是引入以下if-else语句:

if ((textureArray[currentVertexPointer*2] + textureArray[currentVertexPointer*2+1])== 0 ) { //if the index hasn't been populated yet, store it
textureArray[currentVertexPointer*2] = currentTex.x;
textureArray[currentVertexPointer*2+1] = 1.0f - currentTex.y;
} else {
int duplicateVertexPointer = currentVertexPointer;
indices.add(duplicateVertexPointer);
textureArray[duplicateVertexPointer*2] = currentTex.x;
textureArray[duplicateVertexPointer*2+1] = currentTex.y;
}


但是,上述方法的工作原理比以前更糟。现在,该立方体甚至不再呈现为立方体,而是呈现为一个单独的三角形和一个介于其间为空的面。请帮忙 :(

最佳答案

看来您非常接近找出问题所在。是的,某些数据正在被覆盖,因为obj顶点可以在不同的面上具有多个法线或纹理矢量。问题在于,openGL中的顶点属性不是这种情况。

您需要做的是检查您的顶点是否已经具有纹理坐标,是否创建了一个新的顶点并将其与第二个纹理相关联。请注意,这可能会有些混乱。
假设您有一个顶点v1。在不同的面孔上它有几个纹理坐标。

V1-> t1; v1-> t2; v1-> t2。
所以您说V1-> t1,很简单。但是随后您在同一顶点上看到另一个坐标。因此,您克隆了v1,并得到v2-> t2(其中v1 == v2)。
现在是v1-> t2,您不应该创建一个新的顶点v3,因为v2已经存在并且非常适合。

因此,要正确执行此操作,您需要跟踪克隆,并查看它们是否适合组合索引/坐标。

当同时具有法线和纹理坐标时,它变得更加混乱,因为两个面可以共享纹理坐标,但不能共享法线或相反,所有共存都存在。因此,有时您会拥有一个适合特定组合但并非全部适合的克隆。

我做了一个工作正常的obj解析器,但是有点杂乱,所以给您代码将是一种损害。我希望至少能使您走上正确的路。

如果要再次创建解析器,请按以下步骤进行编辑。
每当我在脸上添加一个顶点时,我都会调用以下函数:

vector<vertex> vertices; //All the vertices in my object, this includes the position, texture coordinate and normal
vector<vector<int>> synonyms; // For each vertex, the array of vertices which are the same (cloned vertices)
vector<int> normalIndex;
vector<int> UV index;
int normalIn;
int textureIn;
int vertexIn; //each elements in one point of my face declaration in the obj file vertexIn/textureIn/normalIn

funtion(all of the above)
{

vector<int> synonymsVertex = synonyms[vertexIn]; //We get the synonyms of the vertex we want to add
for(int vertexClone : synonymsVertex)
{
vertex vertexObj = vertices[vertexClone];
//In the case the combination doesn't exist, we clone the vertex and add it to the list
if(vertexObj.normal != normalIn || vertexObj.UV != textureIn)
{
vertex newVertex(vertexObj, normalIn, textureIn);
vertices.push_back(newVertex);
synonymsVertex.push_back(vertices.size - 1);
}
}
}

关于java - 尝试从波前.obj文件加载纹理时,为什么在使用索引渲染(glDrawElements)时纹理显示不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50806126/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com