7
\$\begingroup\$

I am working on simple 2D engine using OpenGL (3.3+) for rendering and was wondering what the optimal method of sprite batching would be. I plan to put all sprites into one (or fewer) texture atlases. Unsurprisingly, each sprite consists of 2 triangles and 4 texture coordinates. For simplicity, let's assume only the sprites are not animated for now.

Now to my question, I do not know what would be the optimal way to draw them. As far as I was able to dig up, I have two options:

  1. Draw each sprite separately, which would allow me to modify the position/rotation/scale of each sprite within the shader via MVP matrices. This also means that I would not need to update the sprite data buffers (vertex pos. & tex. coords) on GPU.

  2. Stuff all sprites' data into a single VBO and draw them all with one glDrawElements call (assuming they use the same texture atlas and shader). However, I would then need to update the VBO every frame (or at least the changed parts, which also means that I would have to watch every sprite's state).

Which of these options is better from a practical point of view? Or is there any other method to achieve what I'm trying to do?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

You aren't limited to having only one MVP per VBO. So you would not in fact need to update the VBO every frame just because you stuff all of your sprites into a single VBO. What I do is store an instance ID with each vertex, which changes only on a per-model basis, and use those instance ID's to index into a uniform array of mat4's, one for each "instance."

\$\endgroup\$
2
\$\begingroup\$

"Which of these options is better from a practical point of view?"

I'll interpret the word "practical" here to be distinct from "theoretically highest performance on a computer"...

At two triangles per sprite, recomputing all the vertices on the host CPU will be not that expensive, & easy to think about.

Or, since all the geometries are the same (two triangles), you may also be able to use glDrawElementsInstanced() which is similar to @Nox's approach.

But really ("practically") start with any technique you like, and if it works even a little, move on. Make sure that somewhere in your code is the high level abstraction, like sprite->setPositionAndRotation(x,y,theta) or whatever. Because getting your game up and running is more important. Later on, optimizing this one detail if needed can be done.

I use a variation of @Nox's answer to move >10000 50ish triangle objects (each different) around in 3d; actually I use a texture rather than a uniform array, but same idea with "instance Id". But I started with using many draw calls (ok up to around 1000 draws), and then manipulating the vertex positions directly in one big buffer, which was fine until I got up in the many thousands...

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .