So I am creating an AR app using Vuforia, and I have found a way to read obj files and index them. But now that I finally got my model to show up, there must be something wrong with my UVs/texture coordinates, as I am getting this:

enter image description here

While in Blender it looks like this:

enter image description here

I think there is something wrong with the way I am indexing it, but I can't seem to figure it out. I am pretty new to all this. It could also be that I am using the texture data in the wrong way somehow.

I am using this code to load the .obj:

bool loadOBJ(
    const char * path, 
    std::vector<glm::vec3> & out_vertices, 
    std::vector<glm::vec2> & out_uvs,
    std::vector<glm::vec3> & out_normals
    printf("Loading OBJ file %s...\n", path);

    std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
    std::vector<glm::vec3> temp_vertices; 
    std::vector<glm::vec2> temp_uvs;
    std::vector<glm::vec3> temp_normals;

    FILE * file = fopen(path, "r");
    if( file == NULL ){
        printf("Impossible to open the file ! Are you in the right path ? See Tutorial 1 for details\n");
        return false;

    while( 1 ){

        char lineHeader[128];
        // read the first word of the line
        int res = fscanf(file, "%s", lineHeader);
        if (res == EOF)
            break; // EOF = End Of File. Quit the loop.

        // else : parse lineHeader

        if ( strcmp( lineHeader, "v" ) == 0 ){
            glm::vec3 vertex;
            fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z );
        }else if ( strcmp( lineHeader, "vt" ) == 0 ){
            glm::vec2 uv;
            fscanf(file, "%f %f\n", &uv.x, &uv.y );
            uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
        }else if ( strcmp( lineHeader, "vn" ) == 0 ){
            glm::vec3 normal;
            fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z );
        }else if ( strcmp( lineHeader, "f" ) == 0 ){
            std::string vertex1, vertex2, vertex3;
            unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
            int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] );
            if (matches != 9){
                printf("File can't be read by our simple parser :-( Try exporting with other options\n");
                return false;
            uvIndices    .push_back(uvIndex[0]);
            uvIndices    .push_back(uvIndex[1]);
            uvIndices    .push_back(uvIndex[2]);
            // Probably a comment, eat up the rest of the line
            char stupidBuffer[1000];
            fgets(stupidBuffer, 1000, file);


    // For each vertex of each triangle
    for( unsigned int i=0; i<vertexIndices.size(); i++ ){

        // Get the indices of its attributes
        unsigned int vertexIndex = vertexIndices[i];
        unsigned int uvIndex = uvIndices[i];
        unsigned int normalIndex = normalIndices[i];

        // Get the attributes thanks to the index
        glm::vec3 vertex = temp_vertices[ vertexIndex-1 ];
        glm::vec2 uv = temp_uvs[ uvIndex-1 ];
        glm::vec3 normal = temp_normals[ normalIndex-1 ];

        // Put the attributes in buffers
        out_uvs     .push_back(uv);
        out_normals .push_back(normal);

    printf("File can be read by our simple parser :-)\n");
    return true;

And this code to index the .obj:

void indexVBO(
    std::vector<glm::vec3> & in_vertices,
    std::vector<glm::vec2> & in_uvs,
    std::vector<glm::vec3> & in_normals,

    std::vector<unsigned int> & out_indices,
    std::vector<glm::vec3> & out_vertices,
    std::vector<glm::vec2> & out_uvs,
    std::vector<glm::vec3> & out_normals
    std::map<PackedVertex,unsigned int> VertexToOutIndex;

    // For each input vertex
    for ( unsigned int i=0; i<in_vertices.size(); i++ ){

        PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]};

        std::map<PackedVertex,unsigned int>::iterator it = VertexToOutIndex.find(packed);
        if ( it == VertexToOutIndex.end() ){
            out_vertices.push_back( in_vertices[i]);
            out_uvs     .push_back( in_uvs[i]);
            out_normals .push_back( in_normals[i]);
            unsigned int newindex = (unsigned int)out_vertices.size() - 1;
            out_indices .push_back( newindex );
            VertexToOutIndex[ packed ] = newindex;
            unsigned int index = it->second;
            out_indices.push_back( index );

Here is my rendering code for the model (Warning: this contains Objective-C):

// Clear colour and depth buffers

// Render video background
[appRenderer renderVideoBackground];


glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(&(object->vertices)[0]));
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(&(object->normals)[0]));
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(&(object->uvs)[0]));



int targetIndex = [[self.vuforiaTrackCaller textureIndexForTarget:name] intValue];

glBindTexture(GL_TEXTURE_2D, [augmentationTexture objectAtIndex:targetIndex].textureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE, (const GLfloat*)&modelViewProjection.data[0]);
glUniform1i(texSampler2DHandle, 0 /*GL_TEXTURE0*/);

glDrawElements(GL_TRIANGLES, object->indices.size(), GL_UNSIGNED_INT, (const GLvoid*)(&(object->indices)[0]));



And how I load the textures (I don't think the problem is here):

// Generate the OpenGL ES texture and upload the texture data for use
// when rendering the augmentation
for (int i = 0; i < [augmentationTexture count]; ++i) {
    GLuint textureID;
    glGenTextures(1, &textureID);
    [[augmentationTexture objectAtIndex:i] setTextureID:textureID];
    glBindTexture(GL_TEXTURE_2D, textureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, [[augmentationTexture objectAtIndex:i] width], [[augmentationTexture objectAtIndex:i] height], 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)[[augmentationTexture objectAtIndex:i] pngData]);
  • \$\begingroup\$ See if you can fix this by flipping V coordinate of UV map - V = 1 - V. It is very common thing that UV gets vertically flipped in different programs/engines. \$\endgroup\$
    – Kromster
    Commented Dec 30, 2016 at 10:08
  • \$\begingroup\$ Oh wow it even states that in the obj loader. I commented the line uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders. and it works. Thank you for giving me a pointer. If you want, you can answer this question for that sweet, sweet reputation :) \$\endgroup\$ Commented Dec 30, 2016 at 10:18
  • \$\begingroup\$ Happy to help. Posted this as answer \$\endgroup\$
    – Kromster
    Commented Dec 30, 2016 at 10:51

1 Answer 1


See if you can fix this by flipping V coordinate of the UV map:

 V = 1 - V

It is very common that UV gets vertically flipped in different programs/engines. Also note that different image formats (and loaders) could also store/flip images vertically.


You must log in to answer this question.

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