PDA

View Full Version : Trouble loading in .obj



veryamateur
12-05-2017, 09:04 PM
Hi, brand new to the forums and needing a bit of help with loading in an obj for an assignment. My model loader reads the obj file, and assigns the values for the vertices, normals, texture mapping and faces to 4 seperate vertex arrays. It then using the faces as an index to create 3 new sorted arrays for the vertices, normals and texture mapping co-ordinates, and uses these sorted arrays to render.
Trouble is the model is a complete mess and looks nothing like it should, although when I try and debug it looks as if the file is being read correctly, and the correct values are being sorted when using the appropriate index. Completely stumped.

The vector3 class contains 3 float values xyz.
sortedvertex, sortednormals and texCoords are all vector arrays of type float.



bool Model::loadModel(char* filename)
{
vector<Vector3> verts;
vector<Vector3> norms;
vector<Vector3> texCs;
vector<unsigned int> faces;

FILE* file = fopen(filename, "r");
if (file == NULL)
{
return false;
}
while (true)
{
char lineHeader[128];

// Read first word of the line
int res = fscanf(file, "%s ", lineHeader);
if (res == EOF)
{
break; // exit loop
}
else // Parse
{
if (strcmp(lineHeader, "v") == 0) // Vertex
{
Vector3 vertex;
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
verts.push_back(vertex);
}
else if (strcmp(lineHeader, "vt") == 0) // Tex Coord
{
Vector3 uv;
fscanf(file, "%f %f\n", &uv.x, &uv.y);
texCs.push_back(uv);
}
else if (strcmp(lineHeader, "vn") == 0) // Normal
{
Vector3 normal;
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
norms.push_back(normal);
}
else if (strcmp(lineHeader, "f") == 0) // Face
{
unsigned int face[9];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &face[0], &face[1], &face[2],
&face[3], &face[4], &face[5],
&face[6], &face[7], &face[8]);
if (matches != 9)
{
// Parser error, or not triangle faces
return false;
}

for (int i = 0; i < 9; i++)
{
double value = face[i] - 1;
faces.push_back(value);
}


}
}
}

// "Unroll" the loaded obj information into a list of triangles.
for (int f = 0; f < (int)faces.size(); f += 3) {

int faceIndex = faces[f];

// first face value (vertex)
sortedvertex.push_back(verts[faces[f]].x);
sortedvertex.push_back(verts[faces[f]].y);
sortedvertex.push_back(verts[faces[f]].z);
vertexCount++;

/*
// second face value (texture mapping)
texCoords.push_back(texCs[faces[f + 1]].x);
texCoords.push_back(texCs[faces[f + 1]].y);
*/

//third face value (normals)
sortednormals.push_back(norms[faces[f + 2]].x);
sortednormals.push_back(norms[faces[f + 2]].y);
sortednormals.push_back(norms[faces[f + 2]].z);
}

verts.clear();
norms.clear();
texCs.clear();
faces.clear();

return true;
}

void Model::render()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
//glEnableClientState(GL_TEXTURE_COORD_ARRAY); disable texturing for now

glVertexPointer(3, GL_FLOAT, 0, &sortedvertex);
glNormalPointer(GL_FLOAT, 0, &sortednormals);
//glTexCoordPointer(2, GL_FLOAT, 0, &texCoords);

glBindTexture(GL_TEXTURE_2D, NULL);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
//glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

didydriver
12-05-2017, 10:41 PM
unsigned int face[9];
for (int i = 0; i < 9; i++)
{
double value = face[i] - 1;
faces.push_back(value);
}

for (int f = 0; f < (int)faces.size(); f += 3) {

int faceIndex = faces[f];

// first face value (vertex)
sortedvertex.push_back(verts[faces[f]].x);
sortedvertex.push_back(verts[faces[f]].y);
sortedvertex.push_back(verts[faces[f]].z);

It should be face[8] with the zero bit counter and only calling for 9 variables. You are also pushing 10 times. You should probably make a comparative in the for loop to assure you will not exceed the bounds of the container also , it looks as if you may be exceeding your values stored. 0 , 3 , 6 , 9 but the size is 9


for (; f+3 < faces.size() );

As far as why your code is looking off I'm not quite sure. And is their a point to subtracting 1 from every face[x].

GClements
12-06-2017, 12:18 AM
glVertexPointer(3, GL_FLOAT, 0, &sortedvertex);
glNormalPointer(GL_FLOAT, 0, &sortednormals);
//glTexCoordPointer(2, GL_FLOAT, 0, &texCoords);


This won't work. You need to use e.g. &sortedvertex[0] to get a pointer to the vector's data.

GClements
12-06-2017, 12:22 AM
It should be face[8] with the zero bit counter and only calling for 9 variables. You are also pushing 10 times.

That's incorrect. There's nothing actually wrong with the way the OBJ is being parsed (in the sense that the vectors will end up containing the correct data).



And is their a point to subtracting 1 from every face[x].
The OBJ format uses 1-based indices. C/C++ arrays and vectors use 0-based indices.

john_connor
12-06-2017, 01:18 AM
unsigned int face[9];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &face[0], &face[1], &face[2],
&face[3], &face[4], &face[5],
&face[6], &face[7], &face[8]);
if (matches != 9)
{
// Parser error, or not triangle faces
return false;
}

in case the model is made up of quads, this piece of code wont detect it, one way to get around it is to first test for 12 uints (4 x vertexindex/texcoordindex/normalindex) and then:

if (matches == 12)
/* process quads */
else if (matches == 9)
/* process triangles */
else
/* error */

what do you expect to see ? is it a 3D model ? if so, did you set up a proper 3D camera / view point to be able to look at your model ?

veryamateur
12-06-2017, 07:22 AM
This won't work. You need to use e.g. &sortedvertex[0] to get a pointer to the vector's data.


This is exactly what fixed the problem. Would have never figured this out myself, this was the last thing I had to do so now I can submit the assignment and put my mind at ease :D
If anyone has the time, could they help in explaining just what was wrong with "&sortedvertex" compared to "&sortedvertex[0]"? In a different render function I refer to a standard array of floats, without using a pointer address or array index and it works perfectly.

Thank you very much for all your replies.

GClements
12-06-2017, 07:45 AM
just what was wrong with "&sortedvertex" compared to "&sortedvertex[0]"?
An array (whether a std::array or a C-style array) is just the data, so a pointer to the array is equivalent to a pointer to the first element.

A std::vector is a structure which contains (amongst other things) a pointer to the data.