c++openglindexingwavefront

OpenGL glDrawElements issues when split into several draw calls


I'm trying to split my buffers into several "ranges"/submeshes, with different materials applied per submesh (my object is an imported .obj file, with a group of faces sharing a material). Using a glDrawElements call on the entire buffer draws the full object, but with textures not changed between submeshes:

glDrawElements(
    GL_TRIANGLES,      // mode
    element_size,      // count of indices
    GL_UNSIGNED_SHORT,   // type
    NULL          // element array buffer offset
);

Result, with the computer and the couch to the left still using brick textures:

enter image description here

If I try to issue a drawcall per material, like this:

for (const auto& [id, mat]: materials_textures) {
    // Send material properties to the shader
    // Omitted a sequence of glUniformX(...)

    // Bind material's textures - omitted
            
    // old non-indexed drawcall that worked - glDrawArrays(GL_TRIANGLES, mat.start_idx, mat.size);
    glDrawElementsBaseVertex(
        GL_TRIANGLES,      // mode
        mat.size,
        GL_UNSIGNED_SHORT,   // type
        NULL,
        mat.start_idx
    );
    std::cout << element_size << " mat.start_idx: " << mat.start_idx << " mat.size: " << mat.size << std::endl;
}

I get only some of the object drawn (note that the glasses are also missing the non-transparent solid lens seen in the top right in the picture above): enter image description here

The drawcall can be replaced with this to no effect:

glDrawElements(
    GL_TRIANGLES,      // mode
    mat.size,
    GL_UNSIGNED_SHORT,   // type
    (void*)(mat.start_idx)
);

With the printout reading:

690 mat.start_idx: 0 mat.size: 330
690 mat.start_idx: 456 mat.size: 174
690 mat.start_idx: 330 mat.size: 90
690 mat.start_idx: 630 mat.size: 60
690 mat.start_idx: 420 mat.size: 36

so the entire range of the buffer should be covered by subsequent draw calls.

I understand that a possible solution could be to split these submeshes into separate .obj files, but is there anything simple I'm missing to keep these together in one file with different materials applied still?


Solution

  • The last argument of glDrawElements isn't the starting index number, it's the byte offset of the first index. Since you're using GL_UNSIGNED_SHORT indices, each one is 2 bytes.

    By the way, OpenGL doesn't care about your obj files or even know they exist, so it doesn't care whether all your data is in one file or several. Your program is the one that handles the files.