I have trouble rendering with glDrawElements

Hello to everyone,

In last two days i have trouble with indices and i am stuck… I exported very simple plane from blender in OBJ format.

I wrote very simple and straightforward parser, looks like this:

FILE *fp = fopen(path, "r");
    if(fp == NULL){
            printf("Model load error: %s\n", path);
    }

    char tmpc[100];

    int v_count = 0;
    int vt_count = 0;
    int vn_count = 0;
    int fv_count = 0;
    int fvt_count = 0;
    int fvn_count = 0;

    /* get v,vt and vn data */
    while(1){
            if( fscanf(fp, "%s", tmpc) == EOF ){
                    break;
            }

            if(strcmp(tmpc, "v") == 0){
                    fscanf(fp, "%f", &ve.v[v_count]);
                    v_count++;
                    fscanf(fp, "%f", &ve.v[v_count]);
                    v_count++;
                    fscanf(fp, "%f", &ve.v[v_count]);
                    v_count++;
            }

            if(strcmp(tmpc, "vt") == 0){
                    fscanf(fp, "%f", &ve.vt[vt_count]);
                    vt_count++;
                    fscanf(fp, "%f", &ve.vt[vt_count]);
                    vt_count++;
                    fscanf(fp, "%f", &ve.vt[vt_count]);
                    vt_count++;
            }

            if(strcmp(tmpc, "vn") == 0){
                    fscanf(fp, "%f", &ve.vn[vn_count]);
                    vn_count++;
                    fscanf(fp, "%f", &ve.vn[vn_count]);
                    vn_count++;
                    fscanf(fp, "%f", &ve.vn[vn_count]);
                    vn_count++;
            }

            if(strcmp(tmpc, "f") == 0){
                    fscanf(fp, "%d/%d/%d", &ve.fv[fv_count], &ve.fvt[fvt_count], &ve.fvn[fvn_count]);
                    fv_count++; fvt_count++; fvn_count++;
                    fscanf(fp, "%d/%d/%d", &ve.fv[fv_count], &ve.fvt[fvt_count], &ve.fvn[fvn_count]);
                    fv_count++; fvt_count++; fvn_count++;
                    fscanf(fp, "%d/%d/%d", &ve.fv[fv_count], &ve.fvt[fvt_count], &ve.fvn[fvn_count]);
                    fv_count++; fvt_count++; fvn_count++;
            }

    }

    }

    glGenBuffers(1, &ve.VBO);
    glBindBuffer(GL_ARRAY_BUFFER, ve.VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(ve.v), ve.v, GL_STATIC_DRAW);

    glGenBuffers(1, &ve.EBO); */
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ve.EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ve.fv), ve.fv, GL_STATIC_DRAW);

    ve.v_size = sizeof(GLfloat) * v_count;
    ve.vt_size = sizeof(GLfloat) * vt_count;
    ve.vn_size = sizeof(GLfloat) * vn_count;
    ve.fv_size = sizeof(GLfloat) * fv_count;
    ve.fvt_size = sizeof(GLfloat) * fvt_count;
    ve.fvn_size = sizeof(GLfloat) * fvn_count;

    // TODO, use ve.x_count variables directly in here, discard local x_count;
    ve.v_count = v_count;
    ve.vt_count = vt_count;
    ve.vn_count = vn_count;
    ve.fv_count = fv_count;
    ve.fvt_count = fvt_count;
    ve.fvn_count = fvn_count;

Every file i threw at it loaded just fine, i checked many times in lldb debugger to see actual values in variables during runtime and everything is fine.

And i render my stuff with this:

void visualEntityRender(visualEntity *ve, GLuint type){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindBuffer(GL_ARRAY_BUFFER, ve->VBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ve->EBO);

        glEnableVertexAttribArray(ve->shaderID);
        glVertexAttribPointer( ve->shaderID, 3,
                               GL_FLOAT, GL_FALSE,
                               0, (void *)0 );

        switch(type){
        case GL_ARRAY_BUFFER: goto ARRAY; break;
        case GL_ELEMENT_ARRAY_BUFFER: goto ELEMENTS; break;
        default: printf("Uknown rendering type.\n"); goto END; break;
        }

ARRAY:
        glDrawArrays(GL_TRIANGLES, 0, ve->v_count);
        goto END;
ELEMENTS:
        glDrawElements(GL_TRIANGLES, ve->fv_count, GL_UNSIGNED_INT, (void*)0);
END:
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glDisableVertexAttribArray(ve->shaderID);
}

Result is this is failure:

So the question is, where am i making mistake? I recently started OpenGL 4, everything goes smoothly including matrix transformations, textures etc… except this… Thank you very much in advance for your time. Feel free to ask me for any part of code you are interested in, also debugger output etc…

I’m assuming the mistake is in thinking you can pass the arrays specified in an OBJ file directly to OpenGL.

Each vertex in an OBJ file has three indices: position, normal, texture coordinates. An OpenGL vertex has one. You need to create an OpenGL vertex for each distinct triple of indices which occurs in the OBJ file. Use an associative array (e.g. std::map or std::unordered_map) to hold the mapping from (v,vn,vt) indices to OpenGL index, and a plain array (or std::vector) to hold the reverse mapping (which you’ll need to generate the attribute arrays).

Thank you so much for reply! The requirement in this project is to use C only. I have no knowledge of C++'s std namespace. Are you saying that i need to somehow combine v,vt,vn in C style array per one vertex?

All three attribute arrays (position, normal, texture coordinates) need to be the same size. Each index in the element array selects the same attribute array entry for all attributes.

As it stands, your code is presumably ignoring the indices for the normal and texture coordinates. Unless the face definitions in the file only use a single index (which is equivalent to specifying the same index for all three properties), that will produce the wrong result. And unless the normal and texture coordinate arrays are at least as large as the position array, you’ll be accessing elements beyond the ends of those arrays. Also: OBJ’s indices start at 1, C and OpenGL array indices start at 0.

If you can’t use C++, you’ll need to find or write an associative array implementation (e.g. hashtable or btree). The C standard library doesn’t include anything suitable. Well, you could just use a plain array, but that will be quite inefficient as you’ll have to scan the array for each vertex in each face definition.

A key-value store such as dbm, gdbm or Berkeley db would work, but those are intended for persistent storage so they’ll perform file I/O which adds some overhead. But those would probably still be faster than using a linear array for large OBJ files.