问题
Given the following rendered objects (dragon with completely white texture) and stall with a basic texture. What might be the error? Are my indices wrong? Are some vertices or faces wrong?
:What could possibly be wrong in my obj-renderer class? I followed a tutorial and unfortunately my model does not look like the desired model. The dragon should be completely white without any black lines and the stall texture looks wrong (white lines which shouldn't be there).
This is the source-code (basic .obj-rendering with "v ", "vt ", "vn ", "f "):
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<Integer> indices,
final List<Vector2f> textures, final List<Vector3f> 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;
}
回答1:
The logic used for combining vertex coordinates, texture coordinates, and normals looks flawed. The clearest sign of why this cannot work is here:
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;
Picture what happens if there are multiple vertices with the same coordinates, but different texture coordinates. Say you have the following index triplets as part of different faces:
f ... 4/7/13 ...
f ... 4/9/13 ...
These are two vertices with the same vertex coordinates, but different texture coordinates. Since the first index is the same, you would be using the same currentVertexPointer
index when you assign values in textureArray
, even though these are two different vertices that need different texture coordinates.
The key point to understand is that since OpenGL uses the same indices for all vertex attributes, you need a vertex for each unique combination of vertex coordinates, texture coordinates, and normals.
One way of interpreting this is that the v
records do not give you vertices. They give you vertex postitions. You extract 3 attributes for each vertex, which are all treated the same:
v
records: positions.vt
records: texture coordinates.vn
records: normals.
You build vertices by combining these 3 attributes. The f
records tell you how to combine them.
The easiest way to build OpenGL vertices is to generate a new vertex for each index triplet you encounter while parsing the faces. If you wanted to get your code running with relatively minimal changes, you could treat your verticesArray
much more like the textureArray
and normalsArray
. Your processVertex()
function would then look something like this:
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;
This will require more related changes. In place of rewriting your whole code, here are at least some pointers:
- As used now,
currentVertexPointer
will need to be incremented for each vertex. - You don't have an upper limit for
verticesArray
,textureArray
andnormalsArray
ahead of time, since the size depends on the number of faces. You'll need to size these arrays dynamically, or use a container that handles this for you. - The later code for building
verticesArray
is not needed anymore, since it is now built with the other arrays. - You don't really need indices for this approach. You can draw with
glDrawArrays()
.
A more efficient solution is to share vertices for each unique combination of position/texture/normal. See my answers Why is my OBJ parser rendering meshes like this? and OpenGL - Index buffers difficulties for directions on how to do that.
Beyond this, your parser is also very limited. OBJ is not really a standardized format, and it all depends on how well you want to handle files from various sources. Aspects that your code is not handling include:
- Face records that are intermixed with other records. Your code assumes that they are all at the end, which is not required.
- Negative indices.
- Faces with more than 3 vertices (see Converting quadriladerals in an OBJ file into triangles?).
来源:https://stackoverflow.com/questions/28370813/what-could-be-wrong-with-my-obj-parser