0

I created an obj model parser and decided to follow the tutorial at http://opengl-tutorial.org, but the parsing of the normals and vertices does not work properly. I decided to change the code a bit to see what would happen and to maybe fix it, but when I did that the outputted vertices completely changed from the way they previously looked. I then noticed a mistake I made in the loop and I fixed it and that made the vertices how they were before, but that only had the front side properly rendered. I don't know what I did wrong and I cannot seem to understand enough how the indices work to figure it out. This is the code, that renders only the front side properly (This is just the vertices, the code for the normals works the same way.):

for(i = 0; i < vertexsize; i += 3){
    verticesind[i] = verticesout[vertexindices[i] - 1];
    verticesind[i + 1] = verticesout[vertexindices[i + 1] - 1];
    verticesind[i + 2] = verticesout[vertexindices[i + 2] - 1];
    verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + sizeof(vertices[i + 2]);
}

For any of you wondering this is the model.obj file:

# Blender v2.93.8 OBJ File: ''
# www.blender.org
o Cube
v 0.500000 0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v -0.500000 0.500000 0.500000
v -0.500000 -0.500000 0.500000
vt 0.875000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.375000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.625000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
s off
f 5/1/1 3/2/1 1/3/1
f 3/2/2 8/4/2 4/5/2
f 7/6/3 6/7/3 8/8/3
f 2/9/4 8/10/4 6/11/4
f 1/3/5 4/5/5 2/9/5
f 5/12/6 2/9/6 6/7/6
f 5/1/1 7/13/1 3/2/1
f 3/2/2 7/14/2 8/4/2
f 7/6/3 5/12/3 6/7/3
f 2/9/4 4/5/4 8/10/4
f 1/3/5 3/2/5 4/5/5
f 5/12/6 1/3/6 2/9/6

One of the top triangles should be

-0.5, 0.5, -0.5,
 0.5, 0.5,  0.5,
 0.5, 0.5, -0.5

and that results in a full triangle, but for some reason they get shuffled around in the final result and the same triangle turns into

-0.5, -0.5, 0.5,
-0.5,  0.5, 0.5,
 0.5, -0.5, 0.5

This is the full code of my function (I don't think it will be needed as I am loading the obj file properly, but it can still be used to check how I save the values):

int load_obj(const char* filename, float* vertices, float* texcoords, float* normals, unsigned int* vertexindexsize, unsigned int* texcoordindexsize, unsigned int* normalindexsize){
    FILE* file = fopen(filename, "r");
    char lineheader[128];
    int res;
    int i = 0;
    int f = 0;
    int d = 0;
    int g = 0;
    unsigned int vertexsize = 0;
    unsigned int texcoordsize = 0;
    unsigned int normalsize = 0;
    unsigned int verticessize = 0;
    unsigned int texturecoordsize = 0;
    unsigned int normalssize = 0;
    float verticesout[500];
    float texcoordsout[500];
    float normalsout[500];
    float verticesind[500];
    float texturecoordsind[500];
    float normalsind[500];
    unsigned int vertexindex[3];
    unsigned int texindex[3];
    unsigned int normalindex[3];
    vec3 vertex;
    vec2 texcoord;
    vec3 normal;
    int vertexindices[500];
    int texindices[500];
    int normalindices[500];
    if(file == NULL){
        printf("Failed to open file!\n");
        return 1;
    }
    while(1){
        res = fscanf(file, "%s", lineheader);
        if(res == EOF){
            break;
        }
        if(strcmp(lineheader, "v") == 0){
            fscanf(file, "%f %f %f\n", &vertex[0], &vertex[1], &vertex[2]);
            verticesout[i] = vertex[0];
            verticesout[i + 1] = vertex[1];
            verticesout[i + 2] = vertex[2];
            i += 3;
        }else if(strcmp(lineheader, "vt") == 0){
            fscanf(file, "%f %f\n", &texcoord[0], &texcoord[1]);
            texcoordsout[f] = texcoord[0];
            texcoordsout[f + 1] = texcoord[1];
            f += 2;
        }else if(strcmp(lineheader, "vn") == 0){
            fscanf(file, "%f %f %f\n", &normal[0], &normal[1], &normal[2]);
            normalsout[d] = normal[0];
            normalsout[d + 1] = normal[1];
            normalsout[d + 2] = normal[2];
            d += 3;
        }else if(strcmp(lineheader, "f") == 0){
            fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexindex[0], &texindex[0], &normalindex[0], &vertexindex[1], &texindex[1], &normalindex[1], &vertexindex[2], &texindex[2], &normalindex[2]);
            vertexindices[g] = vertexindex[0];
            vertexindices[g + 1] = vertexindex[1];
            vertexindices[g + 2] = vertexindex[2];
        vertexsize += 3;
            texindices[g] = texindex[0];
            texindices[g + 1] = texindex[1];
            texindices[g + 2] = texindex[2];
        texcoordsize += 3;
            normalindices[g] = normalindex[0];
            normalindices[g + 1] = normalindex[1];
            normalindices[g + 2] = normalindex[2];
        normalsize += 3;
            g += 3;
        }
    }
    for(i = 0; i < vertexsize; i += 3){
        verticesind[i] = verticesout[vertexindices[i] - 1];
        verticesind[i + 1] = verticesout[vertexindices[i + 1] - 1];
        verticesind[i + 2] = verticesout[vertexindices[i + 2] - 1];
        verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + sizeof(vertices[i + 2]);
    }
    for(i = 0; i < texcoordsize; i++){
        texturecoordsind[i] = texcoordsout[texindices[i] - 1];
        texturecoordsize += sizeof(texturecoordsind[i]);
    }
    for(i = 0; i < normalsize; i += 3){
        normalsind[i] = normalsout[normalindices[i] - 1];
        normalsind[i + 1] = normalsout[normalindices[i + 1] - 1];
        normalsind[i + 2] = normalsout[normalindices[i + 2] - 1];
        normalssize += sizeof(normalsind[i]) + sizeof(normalsind[i + 1]) + sizeof(normalsind[i + 2]);
    }
    memcpy(vertices, verticesind, sizeof(verticesind));
    memcpy(texcoords, texturecoordsind, sizeof(texturecoordsind));
    memcpy(normals, normalsind, sizeof(normalsind));
    *vertexindexsize = verticessize;
    *texcoordindexsize = texturecoordsize;
    *normalindexsize = normalssize;
    return 0;
}
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
RadoslavL
  • 56
  • 6
  • `verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + ...` Do you expect different elements of your array to have different sizes? They don't. – Gerhardh Aug 17 '22 at 09:34
  • You should always check the return value of `scanf` and friends for expected values. – Gerhardh Aug 17 '22 at 09:36
  • For better testability you could remove the part that loads the file and configure the values hardcoded in your example. That would also verify that reading *really* is correct. – Gerhardh Aug 17 '22 at 09:37
  • I checked the fscanf return value and it's correct every single time. As I said, the issue isn't in the part of the code, where I get the values from the file, but rather in the part of the code, where I try to parse the vertices and the normals with their indices from the file. – RadoslavL Aug 17 '22 at 10:16
  • The first problem with the code I've encountered is the way you handle comments. Whenever the # character is found, the rest of the line is to be ignored. Problem is though, you don't read in entire lines at a time. So, if you comment out a vert line, you still read 8 verts. Instead, you can read the entire line, split it up on ' ' characters then check if the first element of the array you get back from strtok is o, v, vt, vn, s or f before handling the line accordingly. You can immediately discard the remainder of the line when you come across a # character. – enhzflep Aug 17 '22 at 11:25
  • The next thing that stands out is the fact you're reading integers from the file for all of the lines beginning with 'f', yet you're stuffing the some of the results into an array of floats. (normalsind holds {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 } when you hit the first memcpy at the bottom of the function) Yet, at the same time verticesind and texturecoordsind hold floats. The 'ind' part of each name seems to indicate that these would all be arrays of indices, not values. – enhzflep Aug 17 '22 at 11:36
  • @enhzflep The reason I made the name of the variables contain "ind" is, because they contain values sorted by indices. I use them accordingly afterwards. As you typed in your own comment - the values, coming out of the parsing stage, are wrong. The normals should contain negative values inside them, but that does not seem to be happening. – RadoslavL Aug 17 '22 at 11:50

1 Answers1

0

I changed the function a bit, as it didn't take use of the indices correctly:

for(i = 0; i < vertexsize; i++){
      verticesind[i * 3] = verticesout[(vertexindices[i] - 1) * 3];
      verticesind[i * 3 + 1] = verticesout[(vertexindices[i] - 1) * 3 + 1];
      verticesind[i * 3 + 2] = verticesout[(vertexindices[i] - 1) * 3 + 2];
      verticessize += sizeof(verticesind[i]) * 3;
}

Now it loads the vertices and normals properly.

RadoslavL
  • 56
  • 6