Search code examples
c++glslvbovao

C++ GLSL Multiple IBO in VAO


I'm developing a small project and I'm using VBO, IBO and VAO, I have an array of vertices, and its respective array indices, I do the same with the materials (since the same vertex can have a different material other side ) but this link in a VAO same does not display anything. For every single VAO must be an IBO?

Attached is my code in which sending data to the gpu and render respectively!

I would appreciate your help, greetings :)

void Upload(){
    GLuint ibo[2], vbo[3];

    glGenBuffers(3, vbo);
    glGenBuffers(2, ibo);
    glGenVertexArrays(1, vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); //Vertices
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vec3), vertices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); //Normales
    glBufferData(GL_ARRAY_BUFFER, vertex_normal.size()*sizeof(vec3), vertex_normal.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, v_indices.size()*sizeof(GLuint), v_indices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); //Material
    glBufferData(GL_ARRAY_BUFFER, materials.size()*sizeof(Material), materials.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size()*sizeof(GLuint), m_indices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glBindVertexArray(vao[0]);
    //Vertices:
    glEnableVertexAttribArray(attrib_vertex);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(attrib_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
    //Normales:
    glEnableVertexAttribArray(attrib_normal);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glVertexAttribPointer(attrib_normal, 3, GL_FLOAT, GL_FALSE, 0, 0);
    //IBO:
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);

    //Materiales:
    for(int i=0; i<5; ++i)
        glEnableVertexAttribArray(attrib_material+i);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
    glVertexAttribPointer(attrib_material, 4, GL_FLOAT, GL_FALSE, sizeof(Material), NULL);
    glVertexAttribPointer(attrib_material+1, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, diffuse));
    glVertexAttribPointer(attrib_material+2, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, specular));
    glVertexAttribPointer(attrib_material+3, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, emission));
    glVertexAttribPointer(attrib_material+4, 1, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, shininess));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]);

    //Desactivando todo:
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(attrib_vertex);
    glDisableVertexAttribArray(attrib_normal);
    for(int i=0; i<5; ++i)
        glDisableVertexAttribArray(attrib_material+i);
}
void Draw(){
    glBindVertexArray(vao[0]);
    glDrawElements(GL_TRIANGLES, v_indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

Solution

  • Each VAO stores the value of the current GL_ELEMENT_ARRAY_BUFFER_BINDING.

    That stored value is set when you call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]) and glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]).

    The problem with your code is that your second call to glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...) is overwriting the value stored by the first call. This happens because each VAO can only store a single value for GL_ELEMENT_ARRAY_BUFFER_BINDING. That is, there is only 1 IBO allowed per VAO.

    Some solutions I propose:

    • You could store the material data differently so that it matches the indices in your mesh. This may mean that you need to duplicate the material data.
    • You could store the material data in uniform buffers, then store the index of the material data within the uniform buffer as a vertex attribute for each vertex.
    • It seems like your material defines the lighting information. Maybe you could split your rendering into multiple passes. (ie. an ambient pass, a diffuse pass, a specular pass...) A rendering method like deferred lighting would make this a non-issue.
    • You could combine the indices of the vertices and the materials into one big IBO. (Might work in combination with other methods I mentioned.)
    • You might be able to use glVertexAttribDivisor if your data fits the pattern.

    Either way, the central issue is that you can only have 1 IBO per VAO. You'll have to be creative to find a solution that fits your use. Good luck!