0

We seem to be having troubles rendering an EBO using indices from an OBJ model. As shown below, we first load and assign the vertex data by iterating through each key word in the OBJ and replicate them values:

CBint                   current_material = -1;
std::vector <vec3>      temp_v;
std::vector <vec3>      temp_vn;
std::vector <vec2>      temp_vt;
for (unsigned int i = 0; i < line.size(); i++)
{
    switch ((line[i])[0])
    {
    case '#':
        continue;
    case '\0':
        continue;
    case 'm':
        char mtl_url[128];
        sscanf_s((&line[i])[0].c_str(), "mtllib %s", mtl_url, sizeof(mtl_url));
        _mtl_url = mtl_url;
        _materialised = true;
        break;
    case 'v':
        float x, y, z;
        if ((line[i])[1] == 'n')
        {
            sscanf_s((&line[i])[0].c_str(), "vn %f %f %f", &x, &y, &z);
            temp_vn.push_back(vec3(x, y, z));
        }
        if ((line[i])[1] == 't')
        {
            sscanf_s((&line[i])[0].c_str(), "vt %f %f", &x, &y);
            temp_vt.push_back(vec2(x, y));
        }
        else
        {
            sscanf_s((&line[i])[0].c_str(), "v %f %f %f", &x, &y, &z);
            temp_v.push_back(vec3(x, y, z));
        }
        break;
    case 'u':
        char material_element[128];
        sscanf_s((&line[i])[0].c_str(), "usemtl %s", &material_element, sizeof(material_element));

        if (_material_elements.size() > 1)
            _f[_f.size() - 1].mat_id = _material_elements.size();

        _material_elements.push_back(material_element);

        current_material++;
        break;
    case 'f':
        CBuint v_i[3];
        CBuint vn_i[3];
        CBuint vt_i[3];

        sscanf_s((&line[i])[0].c_str(), "f %d/%d/%d %d/%d/%d %d/%d/%d", &v_i[0], &vt_i[0], &vn_i[0], &v_i[1], &vt_i[1], &vn_i[1], &v_i[2], &vt_i[2], &vn_i[2]);
        _f.push_back(Face(v_i[0], vt_i[0], vn_i[0], v_i[1], vt_i[1], vn_i[1], v_i[2], vt_i[2], vn_i[2]));
        break;
    }

Then we simply optimize the indices by iterating through each face whilst iterating through each attribute to which are then assigned to the "_indices" container:

for (CBuint i = 0; i < _f.size(); i++)
        {
            for (CBuint j = 0; j < 3; j++)
            {
                CBuint v =  _f[i].v[j];
                CBuint vt = _f[i].vt[j];
                CBuint vn = _f[i].vn[j];

                out_v.push_back(temp_v[v - 1]);
                out_vt.push_back(temp_vt[vt - 1]);
                out_vn.push_back(temp_vn[vn - 1]);

                _indices.push_back(v);
                _indices.push_back(vt);
                _indices.push_back(vn);
            }
        }

The "_f" is an identifier to a vector list of "Face"s which is a simple struct containing:

CBuint v[3];
CBuint vt[3];
CBuint vn[3];
CBuint mat_id;

This is another struct we use ("Mesh") for creating multiple sub-meshes that are defined by each material detected within the OBJ ("usemtl default__0"). We do this so we can render multiple sub-meshes within a model with their rightful material.

Mesh(std::vector <CBuint>& i, std::vector <vec3>& v, std::vector <vec3>& vn, std::vector <vec2>& vt)
        {
            glGenBuffers(1, &vbo_v);
            glEnableVertexAttribArray(0);
            glBindBuffer(GL_ARRAY_BUFFER, vbo_v);
            glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(Math::vec3), &v[0], GL_STATIC_DRAW);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);

            glGenBuffers(1, &vbo_vn);
            glEnableVertexAttribArray(1);
            glBindBuffer(GL_ARRAY_BUFFER, vbo_vn);
            glBufferData(GL_ARRAY_BUFFER, vn.size() * sizeof(vec3), &vn[0], GL_STATIC_DRAW);
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);

            glGenBuffers(1, &vbo_vt);
            glEnableVertexAttribArray(2);
            glBindBuffer(GL_ARRAY_BUFFER, vbo_vt);
            glBufferData(GL_ARRAY_BUFFER, vt.size() * sizeof(vec2), &vt[0], GL_STATIC_DRAW);
            glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);

            glGenBuffers(1, &ebo);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, i.size() * sizeof(CBuint), &i[0], GL_STATIC_DRAW);
        }

After optimising the array of indices ("f x/x/x x/x/x x/x/x"), we iterate through each material element and push_back a mesh for each material:

CBuint next_element = 0;
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
if (_materials.size() > 1)
{
    for (CBuint i = 0; i < _f.size(); i++)
    {
        if (_f[i].mat_id == next_element)
        {
            _meshes.push_back(new Mesh(_indices, out_v, out_vn, out_vt));
            next_element++;
        }
    }
}
else
    _meshes.push_back(new Mesh(_indices, out_v, out_vn, out_vt));
glBindVertexArray(0);

Then finally we call glDrawElements instead of glDrawArrays to save 1/3rd of rendering time:

glUniformMatrix4fv(_u_model, 1, GL_FALSE, _model);

_materials[0]->bind();

glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0); 

Unfortunately, when using glDrawElements we get the following results:

http://s11.postimg.org/5qbsf2uzn/Untitled_1.jpg

However when using glDrawArrays, the results are perfect:

http://postimg.org/image/7wrq8icn3/

Can anyone tell us what we're doing wrong? Further, here is our vertex shader locations code:

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;

If anyone has any idea, we'd appreciate a response. Thank you! DrStrange.

Nicol Bolas
  • 378,677
  • 53
  • 635
  • 829
DrStrange
  • 64
  • 7
  • Thank you for the concern but this doesn't answer my question. I know how the vbo and vertex system works, what I'm asking is how to fix this problem with indices. Thank you. – DrStrange Sep 23 '16 at 14:45
  • Your problem seems me that is at indices generation. You have posted a lot of code that seems me disconnected. What I suggest you is to debug it yourself. Start with a very basic geometry, like a triangle, and look to see if indices are generated correctly. If so, improve your geometry, a quad for example, and do that again.... – Amadeus Sep 23 '16 at 14:51
  • Yeah that was my plan b @Amadeus but I guess that's the best thing to do in this situation. Thanks for the response! – DrStrange Sep 23 '16 at 14:58

0 Answers0