Search code examples
openglvertex-buffer

Is combining instance VBOs a good idea?


Which of the following options is better for per-instance data?

  • One huge VBO with the position of every object, shared by all VAOs, with each VAO having an offset and length
  • One VBO per VAO with only the positions of the instances for its vertex data.
  • Something fancier, like one huge VBO for static objects and one smaller VBO for moving ones

I'm not using multiple VAOs to draw one set of instances. I mean for multiple sets of instances spanning multiple VAOs.


Solution

  • There's really not one single approach that will be best in all cases. If there was only one way that always performs best, APIs like OpenGL would not offer all these flexible options.

    Some factors that will influence what will be best:

    • Performance characteristics of the platform.
    • Number of objects drawn.
    • Size (number of vertices) of objects drawn.
    • If all objects are drawn in each frame, or only a (small) subset.
    • If and how often the vertex data is modified.

    Looking at some typical use cases:

    • Relatively few large objects: VBO binding and draw calls will probably not be a bottleneck no matter what you do. Using a separate VBO per object is fine if that's the most convenient approach.
    • Large number of small objects: Storing groups of objects in the same VBO is probably beneficial. May also want to look into ways to draw groups of related objects with a single draw call.
    • Only a small subset of the "world" is drawn in each frame, e.g. a game where the player changes between rooms: When grouping objects into VBOs, objects that are drawn at the same time (e.g. objects in the same room) should be in the same VBO, and objects that are never drawn at the same time in different VBOs.
    • Subset of vertices is frequently modified: It's likely beneficial to keep the "dynamic" vertices in a separate VBO, and keep other VBOs completely static.

    In all of these scenarios, if you have multiple instances of the same object type, i.e. objects that have the same geometry, you will of course want to share the vertex data between them.

    Now, one of the questions you may ask about these generic guidelines is: What exactly is "many" objects? Where is the limit between "few" and "many"?

    The answer to this depends heavily on the performance characteristics of the hardware/platform. To give at least a rough order of magnitude, I would expect the most common platforms to be able to handle between a few 100,000 and a few million VBO switches and draw calls per second. If you divide that by a target of 60 fps, and want to avoid spending a majority of your total performance budget in this area, I would start worrying about the number of VBO bind and draw calls around a 1000 per frame on lower performance platforms, while high performance platforms might not break a sweat if you go at least an order of magnitude higher.