Search code examples
openglmeshglew3d-modelling

OpenGL Batch render Mesh


I'm using OpenGL, glew and GLFW to code a simple game for a project. I already have a 3D model importer using Assimp and it is handling textures as well.

This is the way I'm drawing one mesh:

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[NORMAL_VB]);
    glNormalPointer(GL_FLOAT, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[TEXCOORD_VB]);
    glTexCoordPointer(2, GL_FLOAT, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[POS_VB]);
    glVertexPointer(3, GL_FLOAT, 0, NULL);

    //Render the triangles
    glDrawArrays(GL_TRIANGLES, 0, m_Entries[i].NumIndices);

My question is how can I render hundred of moving entities using this same mesh but each one has a different world position and rotation?

If I have hundreds of moving entities, each frame I'm rendering the same mesh hundreds of times and I can notice the FPS drop now.

Btw, I'm not using shaders, just simple draw


Solution

  • Since glVertexPointer() (and the other gl<Foo>Pointer() calls) are deprecated in OpenGL 3 and later, I'm assuming that you're not currently using an OpenGL 3+ core profile.

    There are two methods of instanced rendering which are potentially available, both provided via extensions; ARB_Draw_Instanced and ARB_Instanced_Arrays. Either, both, or neither might be available on any particular card/driver.

    ARB_Draw_Instanced provides glDrawArraysInstancedARB(), which works basically like the glDrawArrays call you're already using, but also provides a gl_InstanceId integer variable for use in your shaders, which you can then use to read matrices or whatever other per-instance data you need from a UBO, TBO, or whatever other mechanism you want to use to get that per-instance data into the shader. In theory, this extension could be available in a context as early as OpenGL 1.1.

    ARB_Instanced_Arrays provides glVertexAttribDivisorARB(), which lets you modify the way that particular vertex attributes work. In a vertex shader each subsequent vertex normally gets the next attribute value from the attached buffer. So the first vertex gets the position specified first in the buffer, the second vertex gets the second position, and so on. With this function, you can tell OpenGL to instead advance the data being provided to the shader according to instances, instead of according to vertices. So you can, for example, create a generic vertex attribute containing the world positions of all the instances which are going to be drawn, and tell OpenGL to only update that value between instances, so every vertex of the first instance gets the first value, every vertex of the second instance gets the second value, and so on. From the shader's point of view, these values are now treated as if they were vertex attributes, instead of as uniforms. In theory, this extension could be available in a context as early as OpenGL 2.

    On my hardware, neither of these approaches are usable in an OpenGL 2.1 context (as these extensions, or related ones, aren't exposed). Your computer may be like mine; incapable of doing instanced rendering in an OpenGL 2.1 context. Or yours might support both approaches. Or just one or the other. Likewise, anyone else you give your program to might find that their computer supports one or the other or both or neither. Extensions are like that, and your program should be able to cope, no matter what the host computer supports.

    In my case, rather than deal with separate implementations depending on what the computer supported, the 'easy' solution was to switch to an OpenGL 3+ context, where both interfaces are available in non-extension form.

    glDrawArraysInstanced() (the non-extension version of the above ARB interface) became core in OpenGL 3.1, so is guaranteed to be present in every 3.1 core profile. Similarly, glVertexAttribDivisor() was added to the core profile in OpenGL 3.3, and will be available in every 3.3 core profile.