I\'m having some trouble drawing some 3d objects. I wrote a very simple .obj parser and I know it doesn\'t support all types of .obj files but that\'s fine and for me it doesn\'
The problem is with the way you use the indices. The related key parts of your code are where you store away the vertex, texture coordinate and normal indices in your mesh:
meshIndices.push_back(verticesIndexed);
meshIndices.push_back(texturesIndexed);
meshIndices.push_back(normalsIndexed);
and then where you use these indices to draw:
for (int i = 0; i < mesh->meshIndices.size(); i++) {
glVertexPointer(3, GL_FLOAT, 0, mesh->indexedVertices[0]);
glNormalPointer(GL_FLOAT, 0, mesh->normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, mesh->textureCoords[0]);
glDrawElements(GL_TRIANGLES, mesh->meshIndices[i].size(),
GL_UNSIGNED_SHORT, &mesh->meshIndices[i][0]);
}
What this is doing is draw the mesh 3 times. Once with the vertex indices, once with the texture coordinate indices, and once with the normal indices. This can't possibly end up well. You need to draw once, with the right combination of vertices, texture coordinates, and positions.
The difficulty is that the OBJ format uses separate indices for each vertex attribute (positions, texture coordinates, normals), while OpenGL only supports using a single set of indices for all the attributes.
There are two main approaches to get this working:
Do not use indexing. This is done by applying the index lookup while parsing, and building new arrays that you can then use for rendering without indexing. Sketching out the key parts of your code using this:
if (line.substr(0, 2) == "v ") {
...
indexedVertices.push_back(v);
} else if (line.substr(0, 2) == "vn") {
...
indexedNormals.push_back(v);
} else if (line.substr(0, 2) == "vt") {
...
indexedTextureCoords.push_back(t);
} else if (line.substr(0, 2) == "f ") {
...
unindexedVertices.push_back(
indexedVertices[std::atof(e.at(0).c_str()) - 1]);
unindexedTextureCoords.push_back(
indexedTextureCoords[std::atof(e.at(1).c_str()) - 1]);
unindexedNormals.push_back(
indexedNormals[std::atof(e.at(2).c_str()) - 1]);
}
Then you can use the unindexed attributes, and draw them without indices, using glDrawArrays()
.
The downside is that this replicates shared vertices, so it will consume more memory, and be slower.
You create an OpenGL vertex for each unique combination of indices for vertex, texture coordinate, and normal. My older answer here contains some pseudo-code showing how this can be done: OpenGL - Index buffers difficulties.