我的obj-parser有什么问题?
给定以下渲染对象(具有完全白色纹理的龙)和具有基本纹理的停顿。 可能是什么错误? 我的指数错了吗? 有些顶点或面是错的吗?
:
在我的obj-renderer课程中可能出现什么问题? 我遵循了一个教程,不幸的是我的模型看起来不像所需的模型。 龙应该是完全白色的,没有任何黑线,并且失速纹理看起来不对(白线不应该在那里)。
这是源代码(带有“v”,“vt”,“vn”,“f”的基本.obj渲染):
try { while ((line = reader.readLine()) != null && !line.startsWith("f ")) { String[] currentLine = line.split(" "); if (line.startsWith("v ")) { Vector3f vertex = new Vector3f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3])); vertices.add(vertex); } else if (line.startsWith("vt ")) { Vector2f texture = new Vector2f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2])); textures.add(texture); } else if (line.startsWith("vn ")) { Vector3f normal = new Vector3f(Float.parseFloat(currentLine[1]), Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3])); normals.add(normal); } } textureArray = new float[vertices.size() * 2]; normalsArray = new float[vertices.size() * 3]; do { if (line == null || !line.startsWith("f ")) { continue; } String[] currentLine = line.split(" "); String[] vertex1 = currentLine[1].split("/"); String[] vertex2 = currentLine[2].split("/"); String[] vertex3 = currentLine[3].split("/"); processVertex(vertex1, indices, textures, normals, textureArray, normalsArray); processVertex(vertex2, indices, textures, normals, textureArray, normalsArray); processVertex(vertex3, indices, textures, normals, textureArray, normalsArray); } while ((line = reader.readLine()) != null); reader.close(); } catch (Exception e) { e.printStackTrace(); } verticesArray = new float[vertices.size() * 3]; indicesArray = new int[indices.size()]; int vertexPointer = 0; for (Vector3f vertex : vertices) { verticesArray[vertexPointer++] = vertex.x; verticesArray[vertexPointer++] = vertex.y; verticesArray[vertexPointer++] = vertex.z; } for (int i = 0; i < indices.size(); i++) { indicesArray[i] = indices.get(i); } return loader.loadToVao(verticesArray, textureArray, normalsArray, indicesArray); } private static void processVertex(final String[] vertexData, final List indices, final List textures, final List normals, final float[] textureArray, final float[] normalsArray) { int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1; indices.add(currentVertexPointer); Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1); textureArray[currentVertexPointer * 2] = currentTex.x; textureArray[currentVertexPointer * 2 + 1] = 1 - currentTex.y; 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; }
用于组合顶点坐标,纹理坐标和法线的逻辑看起来有缺陷。 这里无法解决的最明显迹象是:
int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1; indices.add(currentVertexPointer); Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1); textureArray[currentVertexPointer * 2] = currentTex.x; textureArray[currentVertexPointer * 2 + 1] = 1 - currentTex.y;
想象一下,如果有多个顶点具有相同的坐标但纹理坐标不同,会发生什么。 假设您将以下索引三元组作为不同面的一部分:
f ... 4/7/13 ... f ... 4/9/13 ...
这两个顶点具有相同的顶点坐标,但纹理坐标不同。 由于第一个索引是相同的,因此在textureArray
指定值时将使用相同的currentVertexPointer
索引,即使这些是需要不同纹理坐标的两个不同顶点。
要理解的关键点是,由于OpenGL对所有顶点属性使用相同的索引,因此顶点坐标,纹理坐标和法线的每个唯一组合都需要顶点。
解释这一点的一种方法是v
记录不会给你顶点。 他们给你顶点的post 。 您为每个顶点提取3个属性,它们都被视为相同:
-
v
记录:职位。 -
vt
记录:纹理坐标。 -
vn
记录:法线。
您可以通过组合这3个属性来构建顶点。 f
记录告诉你如何组合它们。
构建OpenGL顶点的最简单方法是为解析面时遇到的每个索引三元组生成一个新顶点。 如果您希望以相对较小的更改运行代码,则可以将verticesArray
textureArray
和normalsArray
。 你的processVertex()
函数看起来像这样:
Vector3f currentVertex = vertices.get(Integer.parseInt(vertexData[0]) - 1); verticesArray[currentVertexPointer * 3] = currentVertex.x; verticesArray[currentVertexPointer * 3 + 1] = currentVertex.y; verticesArray[currentVertexPointer * 3 + 2] = currentVertex.z; Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1); textureArray[currentVertexPointer * 2] = currentTex.x; textureArray[currentVertexPointer * 2 + 1] = 1 - currentTex.y;
这将需要更多相关的更改。 代替重写整个代码,这里至少有一些指针:
- 如现在所使用的,
currentVertexPointer
将需要针对每个顶点递增。 - 由于大小取决于面的数量,因此您没有提前使用
verticesArray
,textureArray
和normalsArray
上限。 您需要动态调整这些数组的大小,或者使用一个容器来为您处理这些数组。 - 之后不再需要构建
verticesArray
代码,因为它现在与其他数组一起构建。 - 你真的不需要这种方法的指数。 你可以用
glDrawArrays()
绘制。
更有效的解决方案是为位置/纹理/法线的每个唯一组合共享顶点。 看我的答案为什么我的OBJ解析器渲染这样的网格? 和OpenGL – 索引缓解了如何做到的方向的困难 。
除此之外,您的解析器也非常有限。 OBJ实际上不是一种标准化的格式,它取决于你想要处理来自各种来源的文件的程度。 您的代码未处理的方面包括:
- 与其他记录混合的面部记录。 您的代码假定它们都在最后,这不是必需的。
- 负指数。
- 具有3个以上顶点的面(请参阅将OBJ文件中的quadriladerals转换为三角形? )。