I'm working on a game in a 3D world with 2D sprites only (like Don't Starve game). (OpenGL ES2 with C++)

Currently, I'm ordering elements back to front before drawing them without batch (so 1 element = 1 drawcall). I would like to implement batching in my framework to decrease draw calls.

Here is what I've got for the moment:

  • Order all elements of my scene back to front.
  • Send order list of elements to the Renderer.
  • Renderer look in his batch manager if a batch exist for the given element with his Material.

    • Batch didn't exist: create a new one.
    • Batch exist for element with this Material: Add sprite to the batch.
  • Compute big mesh with all sprite for each batch (1 material type = 1 batch).

  • When all batches are ok, the batch manager compute draw commands for the renderer.

  • Renderer process draw commands (bind shader, bind textures, bind buffers, draw element)

Image with my problem here:

enter image description here

But I've got some problems because objects can be behind another objects inside another batch.

How can I do something like that?

  • \$\begingroup\$ With OpenGL ES2 i don't think it's possible (or at least i can't see how you could do it). Transparency in rasterization is a hard problem and there is not quick fix for it, the classic approach is to split the scene in layers and try to make them work together as best as possible. If you can use more advanced api you can investigate this: en.wikipedia.org/wiki/Order-independent_transparency \$\endgroup\$
    – Raxvan
    Feb 4, 2014 at 13:00
  • 1
    \$\begingroup\$ OIT is good when a sorting by object or by polygon is not possible because there is no single correct order for the polygons, eg two transparent polygons intersect or when rendering really complex transparent meshes. In your case this is not the case. You will not be able to implement it on a mobile device and it is much slower than smartly batching the sprites into as few draw calls as possible. \$\endgroup\$
    – Archy
    Feb 6, 2014 at 8:24

2 Answers 2


A sprite-batch means that all the sprites of the batch exist in the same Z-distance. That means that it isn't possible for one sprite of batch A to be between two sprites of batch B. When that happens, the two sprites of batch B don't actually belong to the same batch and need to be drawn separately.

  • \$\begingroup\$ Ok thanks, so I probably need to implement a mesh batcher but problem is the same :/ \$\endgroup\$
    – user41765
    Feb 5, 2014 at 17:26
  • \$\begingroup\$ GL mandates that primitives are rasterized in order in the given index order within a draw call. You can still batch all sprites into a single call if the streaming VBO is generated back-to-front. That's how depth-dependent particle systems (among other things) can render in a single draw call. Of course, it's much smarter to use cutout transparency or (when applicable) additive-blending so draw order is irrelevant. \$\endgroup\$ Jul 5, 2014 at 3:23

You could do something like this:

  1. Go through list of sprites from back to front

    1.1 sprite already rendered -> next

    1.2 check if 2d sprite extends collide with any sprite in the current batch or with any sprite coming before this one that is not yet marked as rendered (partly overlapping)

    TRUE: continue with next sprite; rendering the current sprite with the current batch may result in sorting issues

    FALSE: add sprite to batch and mark as rendered (eg: flag)

  2. render and clear current batches

  3. still any sprites not flagged as rendered? Resume at 1.

This will lead to an error free result with heavily reduced draw calls. Note: For multiple materials you need to maintain multiple sprite batches during this loop but the algorithm basically stays the same.

  • \$\begingroup\$ Ok thanks, I will try that but it look heavy for a smartphone :s \$\endgroup\$
    – user41765
    Feb 5, 2014 at 17:26
  • \$\begingroup\$ This is much more efficient than rendering every sprite separately and this technique isn't very cpu intensive. Draw calls are expensive because they cost a lot of cpu time. \$\endgroup\$
    – Archy
    Feb 6, 2014 at 8:17

You must log in to answer this question.

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