Updating per object data in modern OpenGL

How should I update per-object data (like transformations and material properties) with modern OpenGL (4.6 core)?

Let’s say I have N meshes to draw each frame. Each mesh has some unique properties, let’s say a transformation matrix and some material properties. Each mesh is drawn with the same shader program. How should one organize transform and material data?

The various methods that come to my mind are the following:

  1. Use uniforms. foreach mesh m: updateUniforms(); draw(m);
    This way, however, data must be sent to the pipeline even if both the material properties and the transformation didn’t change between subsequent frames.

  2. Use N uniform buffers, one for each mesh (or 2N, one storing transformation and the other material data, depending on how likely they are to be updated together). This way there’s no need to send the same data to the GPU each frame if everything stays the same. However, when it comes to sending new transform data, for example, each UBO should be updated individually.

  3. Store everything into 1 uniform buffer (or 2, for the same reasons as above). This way one could batch updates, possibly resulting in better performance. Use glBindBufferRange to select which transform and material to apply to each mesh. With glBindBufferRange, however, one must consider GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, which may require you to pad each individual transform and material data units.

  4. Same as 3. but instead of glBindBufferRange use an offset passed as a uniform:

    glBindBuffer( material UBO);
    glBindBuffer( transform UBO);
    ... 
    foreach mesh m:
        glUniform1i(offset++);
        draw(m);
    

    This way we still have all the benefits (if any) of 3, with the additional cost of updating an integer value (which is a lot less than having to update the actual data as in 1.)

Is 4. a reasonable method to solve the problem? What is the standard way of doing it?

Something you didn’t address: does performance matter here?

How many objects? How many draw calls?

Your description suggests 1 draw call per object. Is this a requirement?

Reason I ask is if/how you batch your objects together into shared draw calls is an important requirement to consider.

I’m experimenting with modern OpenGL with a hobby project, and it’s a very generic renderer with almost no assumptions about its usage (lots of objects drawn with the same shader? a few almost immutable meshes each drawn with a different program? who knows…).

This is why I was wondering what are the most common/standard approaches that could be considered almost always the best choice one could make. For example, to me approach 4. sounds better than 1. (unless really specific needs I guess).

I know UBOs and SSBOs offer some interesting usages that were not possible with uniforms, like batch updates and not having to send the exact same data over and over again to the pipeline, however, I’m not sure if and how I could use those to make the drawing routine more efficient.

I don’t know, I just wanted to know what are the most common options when one has access to modern ogl functions.

How could I batch objects to reduce the number of draw calls without knowing in advance how the application is going to use the renderer (maybe batching is the responsibility of the application and not the renderer?). Could you please point me toward resources where I could get an understanding of what you are talking about?

Well, without any requirements on performance or scene complexity, just do whatever is easiest for your simple renderer.

There’s no sense in making things more complicated unless it buys you something you care about.