Failing to Render an .OBJ Mesh

Started by
4 comments, last by iedoc 12 years, 2 months ago
I've been trying to load in .OBJ file format from a guide I found here http://rastertek.com/dx10tut08.html and it
worked for that box.

However I downloaded another .obj file. And now I get another problem.

This is where I read after I found and 'f' line:


// Read the face data in backwards to convert it to a
left hand system from right hand system.
fileStream >> faces[dwFaceIndex].m_VertexIndex.z >>
input2 >> faces[dwFaceIndex].m_TextureIndex.z
>> faces[dwFaceIndex].m_VertexIndex.y >> input2 >>
faces[dwFaceIndex].m_TextureIndex.y
>> faces[dwFaceIndex].m_VertexIndex.x >> input2 >>
faces[dwFaceIndex].m_TextureIndex.x;



It has only v and vt attributes so it looks like these:

The orginal however did only have 3 sets of numbers but this one can vary from 3 to 4,
any idea on how I solve this? This model varies from 3-4 vertices


f 2/2 1/1 64/64 65/65
f 41/41 64/64 1/1
f 4/4 3/3 1/1 2/2
f 41/41 1/1 3/3
f 6/6 5/5 3/3 4/4
f 41/41 3/3 5/5 f 8/8 7/7 5/5 6/6



Looks like this: f6201284303PMa268.jpg

And it's read because I'm just returning it by default but I'm guessing that 4th value is missing and messing up faces.

Full Code: Normals are nulled since there aren't any in my .OBJ files

bool ObjMeshLoader::LoadDataStructures(std::string& aFileName, Model* aModel)
{
Vector3f *vertices, *texcoords, *normals;
Face *faces;
int vIndex, tIndex, nIndex;
char input, input2;

std::ifstream fileStream;
std::ofstream fileOutput;vertices = new Vector3f[m_dwVertexCount];
if (!vertices)
{
return false;
}
texcoords = new Vector3f[m_dwTextureCount];
if (!texcoords)
{
return false;
}normals = new Vector3f[m_dwNormalCount];
if (!normals)
{
return false;
}
faces = new Face[m_dwFaceCount];
if (!faces)
{
return false;
}int dwVertexIndex = 0;
int dwTexcoordIndex = 0;
int dwNormalIndex = 0;
int dwFaceIndex = 0;
fileStream.open(aFileName);if (fileStream.fail() == true)
{
return false;
}
// Read in the vertices, texture coordinates, and normals into the data structures.
// Important: Also convert to left hand coordinate system since Maya uses right hand coordinate system.
fileStream.get(input);
while (!fileStream.eof())
{
if (input == 'v')
{
fileStream.get(input); // Read in the vertices.
if (input == ' ')
{
fileStream >> vertices[dwVertexIndex].x >> vertices[dwVertexIndex].y >> vertices[dwVertexIndex].z;
// Invert the Z vertex to change to left hand system.
vertices[dwVertexIndex].z = vertices[dwVertexIndex].z * -1.0f;
dwVertexIndex++;
} // Read in the texture uv coordinates.
if (input == 't')
{
fileStream >> texcoords[dwTexcoordIndex].x >> texcoords[dwTexcoordIndex].y;
// Invert the V texture coordinates to left hand system.
texcoords[dwTexcoordIndex].y = 1.0f - texcoords[dwTexcoordIndex].y;
dwTexcoordIndex++;
} // Read in the normals.
if (input == 'n')
{
fileStream >> normals[dwNormalIndex].x >> normals[dwNormalIndex].y >> normals[dwNormalIndex].z;
// Invert the Z normal to change to left hand system.
normals[dwNormalIndex].z = normals[dwNormalIndex].z * -1.0f;
dwNormalIndex++;
}
} // Read in the faces.
if(input == 'f')
{
fileStream.get(input);
if (input == ' ')
{
// Read the face data in backwards to convert it to a left hand system from right hand system.
fileStream >> faces[dwFaceIndex].m_VertexIndex.z >> input2 >> faces[dwFaceIndex].m_TextureIndex.z// >> input2 >> faces[dwFaceIndex].m_NormalIndex.z
>> faces[dwFaceIndex].m_VertexIndex.y >> input2 >> faces[dwFaceIndex].m_TextureIndex.y// >> input2 >> faces[dwFaceIndex].m_NormalIndex.y
>> faces[dwFaceIndex].m_VertexIndex.x >> input2 >> faces[dwFaceIndex].m_TextureIndex.x;// >> input2 >> faces[dwFaceIndex].m_NormalIndex.x;
dwFaceIndex++;
}
}
// Read in the remainder of the line.
while (input != '\n')
{
fileStream.get(input);
} fileStream.get(input);
}
fileStream.close();

VertexPosUVNorm *vertexes = new VertexPosUVNorm[m_dwFaceCount * 3];
if (!vertexes)
{
return false;
}int *indices = new int[m_dwFaceCount * 3];
if(!indices)
{
return false;
}

int vertexCount = 0;
m_dwModelIndexCount = 0;
// Now loop through all the faces and output the three vertices for each face.
for (int index = 0; index < dwFaceIndex; index++)
{
vIndex = faces[index].m_VertexIndex.x - 1;
tIndex = faces[index].m_TextureIndex.x - 1;
nIndex = faces[index].m_NormalIndex.x - 1; vertexes[vertexCount].m_Pos.x = vertices[vIndex].x;
vertexes[vertexCount].m_Pos.y = vertices[vIndex].y;
vertexes[vertexCount].m_Pos.z = vertices[vIndex].z;
vertexes[vertexCount].m_Tex.x = texcoords[tIndex].x;
vertexes[vertexCount].m_Tex.y = texcoords[tIndex].y; //vertexes[vertexCount].m_Norm.x = normals[nIndex].x;
//vertexes[vertexCount].m_Norm.y = normals[nIndex].y;
//vertexes[vertexCount].m_Norm.z = normals[nIndex].z;
indices[vertexCount] = vertexCount;
m_dwModelIndexCount++; vertexCount++;

vIndex = faces[index].m_VertexIndex.y - 1;
tIndex = faces[index].m_TextureIndex.y - 1;
nIndex = faces[index].m_NormalIndex.y - 1;
vertexes[vertexCount].m_Pos.x = vertices[vIndex].x;
vertexes[vertexCount].m_Pos.y = vertices[vIndex].y;
vertexes[vertexCount].m_Pos.z = vertices[vIndex].z; vertexes[vertexCount].m_Tex.x = texcoords[tIndex].x;
vertexes[vertexCount].m_Tex.y = texcoords[tIndex].y;
//vertexes[vertexCount].m_Norm.x = normals[nIndex].x;
//vertexes[vertexCount].m_Norm.y = normals[nIndex].y;
//vertexes[vertexCount].m_Norm.z = normals[nIndex].z; indices[vertexCount] = vertexCount;
m_dwModelIndexCount++;
vertexCount++; vIndex = faces[index].m_VertexIndex.z - 1;
tIndex = faces[index].m_TextureIndex.z - 1;
nIndex = faces[index].m_NormalIndex.z - 1;
vertexes[vertexCount].m_Pos.x = vertices[vIndex].x;
vertexes[vertexCount].m_Pos.y = vertices[vIndex].y;
vertexes[vertexCount].m_Pos.z = vertices[vIndex].z; vertexes[vertexCount].m_Tex.x = texcoords[tIndex].x;
vertexes[vertexCount].m_Tex.y = texcoords[tIndex].y;
//vertexes[vertexCount].m_Norm.x = normals[nIndex].x;
//vertexes[vertexCount].m_Norm.y = normals[nIndex].y;
//vertexes[vertexCount].m_Norm.z = normals[nIndex].z; indices[vertexCount] = vertexCount;
m_dwModelIndexCount++;
vertexCount++;
}m_dwModelVertexCount = vertexCount;

int dwVertexSize = sizeof(VertexPosUVNorm)*m_dwModelVertexCount;
aModel->m_VertexDataWrapper.m_pVertexData = new char[dwVertexSize];
memcpy(aModel->m_VertexDataWrapper.m_pVertexData, vertexes, dwVertexSize);

int dwIndexSize = sizeof(int)*m_dwModelIndexCount;

aModel->m_IndexDataWrapper.m_pIndexData = new char[dwIndexSize];
memcpy(aModel->m_IndexDataWrapper.m_pIndexData, indices, dwIndexSize);//Surface Set
Surface* pSurface = new Surface();
pSurface->SetIndexCount(m_dwModelIndexCount);
pSurface->SetIndexStart(0);
pSurface->SetVertexCount(m_dwModelVertexCount); //Not used.
pSurface->SetVertexStart(0);pSurface->SetPrimologyType(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
pSurface->SetDiffuseTexture("seafloor.dds");aModel->m_vecSurfaces.push_back(pSurface);
//
if (vertices)
{
delete [] vertices;
vertices = NULL;
}if (texcoords)
{
delete [] texcoords;
texcoords = NULL;
}
if (normals)
{
delete [] normals;
normals = NULL;
}if (faces)
{
delete [] faces;
faces = NULL;
}
if (vertexes)
{
delete [] vertexes;
vertexes = NULL;
}if (indices)
{
delete [] indices;
indices = NULL;
}
return true;
}
Advertisement
You should un-strike through your post and point out what was wrong, people might find this topic useful and could learn from your code.
New question :)
it sounds like you have two problems. first is you don't know how to deal with having only 2 vertex components, v and vt, which is the position and tex coords, instead of having 3, pos, tex coords, and normal, right? Second is reading in polygons with more than 3 sides.

Both of these are simple enough. obj formats define faces on the line starting with f as you know. each vertex is defined by one to three components, in order from position, tex coord, and normal. when only a position is defined, a face line might look like this:

f 0 1 2

when there is a position and tex coord, a line might look like this:

f 0/0 1/1 2/2

when all three, position, tex coord, and normal are specified, a line might look like this:

f 0/0/0 1/1/1 2/2/2

and finally, when only a position and normal is specified, the line might look like this:

f 0//0 1//1 2//2

the obj model you have above uses a position and tex coord like you say. in your obj model loader code, you will read the first number of the vertex in the face as the position. you will then read the slash "/" and then read whats after that "/". if it is another number, then you know a texture coordinate is also specified. however, if the next thing is ANOTHER "/", then you know that there is no texture coordinate, but a normal instead. If the next thing read is a space, then you know that only a position was specified, and the next number is another vertex's position. I hope that makes sense

and for the second problem, reading obj models that define faces with more than 3 sides. This is actually pretty easy. lets take the face:

f 0 1 2 3 4

as you can see, this face has 5 sides. before i get into this, the method we will use does not work for "convex" polygons (usually), only "concave" polygons.

When we read this face, we will actually be creating 3 triangles out of it. the first triangle uses the first 3 vertices specified, every vertex after that is a new triangle. we will make the new triangle with the very first vertex defined, and the last vertex defined in the last triangle. this is more easily explained through example:

t1 0 1 2
t2 0 2 3
t3 0 3 4


you can see that all three triangles used the vertex "0", which is the first vertex defined in the face. then each triangle uses the last vertex defined in the triangle before it. I hope that helps, otherwise check out my direct3d 11 lesson on loading obj models which probably explains it at least a little better than i just did ;) good luck

http://www.braynzars...p=D3D11OBJMODEL
if (input == 'f')
{
fileStream.get(input);
if (input == ' ')
{


I don't know how to get if there is 3 or 4 "sets" as the first face has 4 and the second has 3:

XX/XX XX/XX XX/XX XX/XX
XX/XX XX/XX XX/XX

If I could count them to 4 or 3.
Then somehow parse them into respective vectors.
Without breaking the loop.

if (count == 4)
{
fileStream >> faces[dwFaceIndex].m_VertexIndex.w >> input2 >> faces[dwFaceIndex].m_TextureIndex.w
>> faces[dwFaceIndex].m_VertexIndex.z >> input2 >> faces[dwFaceIndex].m_TextureIndex.z
>> faces[dwFaceIndex].m_VertexIndex.y >> input2 >> faces[dwFaceIndex].m_TextureIndex.y
>> faces[dwFaceIndex].m_VertexIndex.x >> input2 >> faces[dwFaceIndex].m_TextureIndex.x;
}
else
{
fileStream >> faces[dwFaceIndex].m_VertexIndex.z >> input2 >> faces[dwFaceIndex].m_TextureIndex.z
>> faces[dwFaceIndex].m_VertexIndex.y >> input2 >> faces[dwFaceIndex].m_TextureIndex.y
>> faces[dwFaceIndex].m_VertexIndex.x >> input2 >> faces[dwFaceIndex].m_TextureIndex.x;
}
You have to "retriangulate" the face or whatever if there is more than 3 vertices defined in the face. So, when you read in a face (the line starting with "f"), you will read 3 vertices because you cannot have a face with less than 3 vertices, so you start by reading in 3 vertices. After you have read 3 vertices, you check to see if there is another vertex on the same line. If there is STILL another vertex, you will make a whole new triangle, using the first vertex defined in the face, the last vertex defined in the last triangle created, and the new vertex. I think i'm making this sound much more complicated than it really is, so let me show you with some pseudocode.

case 'f':
int firstVertexInFace = 0;
int lastVertexInLastTri = 0;

// Read first triangle in face
for(int i = 0; i < 3; i++) // Loop through 3 vertices that make up this first triangle
{
// Read in vertex here and store it in the index list
fileIn.get(readVertex);
indices[indexCount] = readVertex;
indexCount++;

// Now check if we are on the first vertex in the face, or the 3rd vertex in the face. Remember, the third vertex will be used as the second vertex in the next triangle
if(i == 0)
firstVertexInFace = i;
if(i == 2)
lastVertexInLastTri = i;
}

// Increment the triangle count
triCount++;

// Now we have one triangle in the face. if the face has more than 3 vertices, we will create additional triangles for each "extra" vertex

while(nextChar != "\n") // Loop until the end of the line is reached
{
// Now we define another triangle using the first vertex in the face, and the last vertex in the last triangle
indices[indexCount] = firstVertexInFace;
indexCount++;

indices[indexCount] = lastVertexInLastTri;
indexCount++;

// Now read in the next vertex
fileIn.get(readVertex);
indices[indexCount] = readVertex;
indexCount++;

lastVertexInLastTri = readVertex;
}

This topic is closed to new replies.

Advertisement