1
\$\begingroup\$

It's been something like a week and i still can't sort this out. I need something that converts a .obj file into data readable and drawable by my framework. I have 1 main issues: indices. I think i'm getting the vertices right (i checked in the debugger and everything was fine) but when i draw my model something always goes wrong. I see the shape of the model but some triangles are not seen. I think this is a problem of clockwise/counterclockwise drawing. I exported a cube from blender to see how is done and i took pen and paper and draw it by hand following the indices the program created for me and i saw it uses a different indexing order that doesn't work in my program. For i cube i create 36 vertices using the indices described by the "f" word. Every vertex has texture coordinates and normal vectors. Than from the indices i take the vertices indices and i use those to draw the cube, but it doesn't work. I followed this tutorial to get into how i should script the converter ( http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/ ) and i modified the code to make it work for DirectX drawing (which is similar to OpenGL i think) but it doesn't work at all. This is how the cube should look like

This is what i get (rotating around the cube make it look different)

Other view of what i get

void OBJLoader::loadOBJFromFile(char * fileName, std::vector<Vertex::Basic32> &output, std::vector<UINT> &vertexIndicesFinal)
{
    UINT numberOfVertices = 0, numberOfNormals = 0, numberOfUVs = 0, numberOfFaces=0;
    std::vector<Vertex::Basic32> outputDaMettere;
    std::vector< UINT> vertexIndices, uvIndices, normalIndices;
    std::vector< XMFLOAT3 > temp_vertices;
    std::vector< XMFLOAT2 > temp_uvs;
    std::vector< XMFLOAT3 > temp_normals;

    std::vector<XMFLOAT3> outVertices;
    std::vector<XMFLOAT3> outNormals;
    std::vector<XMFLOAT2> outUvs;

    FILE * file = fopen(fileName, "r");
    if (file == NULL) {
        MessageBox(0, L"NULL FILE", 0, 0);
    }
    while (1) {
        char lineHeader[128];
        int res = fscanf(file, "%s \n", lineHeader);
        if (res == EOF)   
            break;

        if (strcmp(lineHeader, "v") == 0) {
            XMFLOAT3 vertex;
            int a = fscanf(file, "%f %f %f \n", &vertex.x, &vertex.y, &vertex.z);
            temp_vertices.push_back(vertex);
            numberOfVertices++;
        }
        else if (strcmp(lineHeader, "vt") == 0) {
            XMFLOAT2 uv;
            fscanf(file, "%f %f\n", &uv.x, &uv.y);
            temp_uvs.push_back(uv);
            numberOfUVs++;
        }
        else if (strcmp(lineHeader, "vn") == 0) {
            XMFLOAT3 normals;
            fscanf(file, "%f %f %f \n", &normals.x, &normals.y, &normals.z);
            temp_normals.push_back(normals);
            numberOfNormals++;
        }
        else if (strcmp(lineHeader, "f") == 0) {
            std::string vertex1, vertex2, vertex3;
            UINT vertexIndex[3], uvIndex[3], normalIndex[3];
            int matches = fscanf(file, "%i %i %i %i %i %i %i %i %i \n", &vertexIndex[0], &uvIndex[0], &normalIndex[0],
                &vertexIndex[1], &uvIndex[1], &normalIndex[1],
                &vertexIndex[2], &uvIndex[2], &normalIndex[2] );

            if (matches != 9) {
                MessageBox(0, L"File cant be read", 0, 0);
                break;
            }
                vertexIndices.push_back(vertexIndex[0]);  
                vertexIndices.push_back(vertexIndex[1]);
                vertexIndices.push_back(vertexIndex[2]);
                uvIndices.push_back(uvIndex[0]);
                uvIndices.push_back(uvIndex[1]);
                uvIndices.push_back(uvIndex[2]);
                normalIndices.push_back(normalIndex[0]);
                normalIndices.push_back(normalIndex[1]);
                normalIndices.push_back(normalIndex[2]);
                numberOfFaces++;
        }
    }
    numberOfFaces *= 3;
    int cont = 0;
    for (int i = 0; i < numberOfFaces; i++) {

        UINT vertexIndex = vertexIndices[i];
        UINT normalIndex = normalIndices[i];
        UINT uvIndex = uvIndices[i];
        Vertex::Basic32 temp;
        temp.Pos = temp_vertices[vertexIndex - 1];
        temp.Normal = temp_normals[normalIndex - 1];
        temp.Tex = temp_uvs[uvIndex - 1];

        output.push_back(temp);

        cont++;
    }
for (int i = 0; i < numberOfFaces; i++) {
            vertexIndices[i]--;  //Starts from 1, i need it to start from 0
        }
    int toAdd = 0;
    for (int i = 0; i < numberOfFaces; i += 3) { //Needed to get the indices working for my draw function
        vertexIndices[i] += toAdd;
        vertexIndices[i + 1] += toAdd;
        vertexIndices[i + 2] += toAdd;
        toAdd += 2;
    }
    vertexIndicesFinal = vertexIndices;


}

I really need this to work, or some other code that does work and that is not impossible to understand. Thanks.

\$\endgroup\$
  • \$\begingroup\$ Look into your obj file and search for the faces descriptions, how many vertex ids are there? If 4, then you need to triangulate the faces when you export into vbo. \$\endgroup\$ – Bálint Mar 26 '17 at 19:24
  • \$\begingroup\$ Bálint they are triangles. I found out that .fbx has an open pre-builded reader so i think i'll go with that. Leaving the question open until i can read .fbx files, after that i'll delete it \$\endgroup\$ – Emanuele Mar 26 '17 at 19:39
  • \$\begingroup\$ Take a look at WaveFrontReader.h. \$\endgroup\$ – Chuck Walbourn Mar 27 '17 at 4:37
1
\$\begingroup\$

You are indeed correct to use Draw. The reason is that the .obj file format is a little bit deceiving (and im going off my own recollection since I tried to erase the trauma).

You basically get a list of vertex points, normals and texture coords referenced by an index. Those indexes are based upon the list of vt, vn, v's you loaded in.

The indexes for a face you see are in a format such as f 1/4/6 which is a reference to vertex location/normal/texture. This ends up making your actual complete vertex point. Yes, they are indexes, but they aren't indicies for use in drawing, just in composing the complete vertex point.

So, when you compose your face, you can add an index for each point but it doesn't really do much, in fact as you probably have worked out its slower.

By rights, you could have an index buffer of 36 indices, and only 24 vertex points (each face has 4 points with texture uvs and normals). But at the moment, upon loading you are creating 36 individual vertex points.

If you wanted to use indicies, you would need to scan the complete 36 vertices and eliminate the 12 duplicates and create an indice list.

Yes, I know your pain on this one...

\$\endgroup\$
  • \$\begingroup\$ At the end i used assimp and i solved everything with a simple importer found on internet \$\endgroup\$ – Emanuele Apr 24 '17 at 9:55
0
\$\begingroup\$

Solved by using

deviceContext -> Draw ()

Instead of

deviceContext -> DrawIndexed()

Indices were totally wrong, but by drawing triangle by triangle with that method i solved. I think is heavier than the other one but it works

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.