0
\$\begingroup\$

I wrote a simple *.obj parser reading read vertices, texcoords and normals. But when I draw a model the texture isn't mapped correctly.

I have already tried uv.y = 1.0f - uv.y to get inverted Y axis coordinates as suggested by a few people but my textures are still displayed skewed.

this is how it currently looks

I know that both texture file and rendering code are correct. Because when I render a plane and use hand written and hard coded texture coordinates and vertices it renders fine. I can render a textured cube by hand fine, too.

this is how it should look

I use an index buffer to store vertex elements and I use the face elements provided by the *.obj file to fill texture coordinate buffer and normal buffer.

Model::Model(const string &givenName, const string &filePath){
    name = givenName;

    std::ifstream in(MODEL_PATH+filePath, std::ios::in);
    if(!in){
        error("Model \"" + filePath + "\" does not exist");
        return;
    }


    ModelMeshIndex tempindex;

    vector<vec3> normals;
    vector<vec2> uvs;

    string line;
    while(getline(in, line)){
        if(line.substr(0,2) == "v "){
                    std::istringstream s(line.substr(2));
                    vec3 v(0.0f);
                    s >> v.x >> v.y >> v.z;
                    data.vertices.push_back(v);
        }
        else if(line.substr(0,2) == "vt"){
                    std::istringstream s(line.substr(2));
                    vec2 v(0.0f);
                    s >> v.x >> v.y;
                    //v.y = 1.0f-v.y;
                    uvs.push_back(v);
        }
        else if(line.substr(0,2) == "vn"){
                    std::istringstream s(line.substr(2));
                    vec3 v(0.0f);
                    s >> v.x >> v.y >> v.z;
                    normals.push_back(v);
        }
        else if(line.substr(0,2) == "f "){
                    std::istringstream s(line.substr(1));
                    char tmp; // For the slashes between elements
                    unsigned short a,b,c, d,e,f, g,h,i;
                    s >> a >> tmp >> d >> tmp >>g;
                    s >> b >> tmp >> e >> tmp >>h;
                    s >> c >> tmp >> f >> tmp >>i;
                    a--; b--; c--; d--; e--; f--; g--; h--; i--;
                    data.index.vertexElements.push_back(a);
                    data.index.vertexElements.push_back(b);
                    data.index.vertexElements.push_back(c);

                    data.index.uvElements.push_back(d);
                    data.index.uvElements.push_back(e);
                    data.index.uvElements.push_back(f);

                    data.index.normalElements.push_back(g);
                data.index.normalElements.push_back(h);
                    data.index.normalElements.push_back(i);
        }
        else if(line[0] == '#') continue;
        else continue;
    }

    for(unsigned int i = 0; i < data.index.normalElements.size(); ++i)
        data.normals.push_back(normals[data.index.normalElements[i]]);

    for(unsigned int i = 0; i < data.index.uvElements.size(); ++i)
        data.uvs.push_back(uvs[data.index.uvElements[i]]);

    //data.uvs.push_back(vec2( 0.0f, 0.0f)); // bottom left
    //data.uvs.push_back(vec2( 0.0f, 1.0f)); // top left
    //data.uvs.push_back(vec2( 1.0f, 0.0f)); // bottom right
    //data.uvs.push_back(vec2( 1.0f, 1.0f)); // top right

    good = true;
}

What is wrong with my parser?

\$\endgroup\$
9
  • \$\begingroup\$ One minor point, you can read multiple values in at once: s >> v.x; s >> v.y; s >> v.z; becomes s >> v.x >> v.y >> v.z; It makes it a bit cleaner. \$\endgroup\$
    – DaleyPaley
    May 7, 2013 at 7:44
  • \$\begingroup\$ To answer your question, it seems like you are assuming a particular format (and number) of vertices for each face. I believe the obj format is more flexible, so it might be reading wrong data. Just a thought. \$\endgroup\$
    – DaleyPaley
    May 7, 2013 at 7:47
  • \$\begingroup\$ I am exporting the obj with triangulated faces, but nothing I can see doesn't match my data format. \$\endgroup\$ May 7, 2013 at 7:51
  • \$\begingroup\$ All I can suggest is to write a minimal obj file by hand, and dump your mesh data to your log after it has been read to see where the discrepancy lies. Or view it in the debugger. \$\endgroup\$
    – DaleyPaley
    May 7, 2013 at 8:09
  • 4
    \$\begingroup\$ Are you sure that some of the vertices don't share the vertex coordinates? (even if they are triangulated). If they do share them, you'll need to duplicate those vertices. \$\endgroup\$
    – c0d3rguy
    May 9, 2013 at 7:27

2 Answers 2

7
\$\begingroup\$

This may be a winding issue. Are you sure that the texture coordinates are parsed in the right sense of rotation?

However, this how you should debug you program.

  • Draw in wire frame mode to find out how the rectangle is composed out of two triangles. The OpenGL command for this is glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);.
  • Use a texture with a gradient fading between four different colors located at the corners. This way you can exactly check how the texture is mapped.

You already know that texture mapping is wrong, but you don't know in which way. Therefore you should perform the two steps above. I have a good day, so I made you such a gradient texture. Click to enlarge.

gradient texture

It is very likely that you can fix the issue by your self then. Otherwise please update your question with screenshots of those debugging steps so that we can provide further help.

\$\endgroup\$
0
\$\begingroup\$

I have found my issue. When reading from an index, which I was, it seems that OpenGL reads textures from the same element of the vector that the index buffer points to for each vertex. I have fixed this issue by loading all of the vertices, textures and normals into seperate buffers and setting buffers to point to the data then drawing with glDrawArrays()

Thank you for the help!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .