I am working with a 2D game in OpenGL ES and have a question about z-order together with a texture atlas.

I am using an orthographic projection because I want pixel-perfect rendering of 2D sprites, however from what I can determine the draw order is really the only thing that will determine which textures (sprites) appear above or below their neighbors.

That is, the "z-index" is a function of the order in which the textures are drawn as opposed to the z coordinate on the vertex array being drawn.

So.. I have a texture atlas to save binding multiple textures for each draw call but this immediately creates a problem if there is more than one atlas in play. If I need to draw textures from more than one atlas (typically the case if I have too many sprites to fit in a single atlas of a reasonable size), then I can't maintain a "draw order" across atlases unless I want to bind/unbind the atlas textures more than once.. which kinda defeats the purpose.

Does anyone have any clues as to what the best approach is here? Currently I'm running under an assumption that I will have to declare different fixed "depths" (e.g foreground, background etc) in my 2D scene and assume that the z-order for sprites at a given depth is the same. Then I can have as many atlases as I need at each depth and simply draw the depths in order (along with their associated atlases)

I'd love to hear what other people are doing.


1 Answer 1


Detailed illustration:

 0   0.25      1
 +----+--------+  0  <-- this is your sprite sheet
 | A  | B      |
 |    +--------+  0.5
 |    | C      |
 +----+--------+  1.0

Let's assume that you have a sprite sheet with defined order of sprites C,B,A

The following methods allow you to draw the sprites in any order using z-buffer.

  • instead of defining in the sprite sheet only 2 coordinates per vertex (u & v), add a third attribute 's' for depth to each texture coordinate:
    • A = [0,0, .6], [0.25, 0, .6], [0,1, .6], [0.25, 1, .6];
    • B = [0.25, 0, .5], [1.0, 0, .5], [0.25, 0.5, .5], [1.0, 0.25, .5]
    • At vertex shader you can copy the last value from the vertex attribute (the constant .5 or .6) to the z-component of gl_Position. Then the rendering pipeline will perform depth test for each quad / triangle to be drawn and always draw B on top of A.

Alternative: Add the 'depth' to u-coordinate.

  • A = [5.0, 0], [5.25, 0], [5.0, 1.0], [5.25, 1.0]
  • set texture wrapping so, that u-coordinate wraps
  • then 5.0 will be handled as 0.0
  • set v-coordinate handling mode to clamp
  • Then 1.0 and 1.1 and 5.0 will be treated as 1.0
  • again in vertex shader copy the integer part of u-coordinate to z-value (and multiply e.g. by 0.01 because |z|>1 will be clipped off...

The other alternatives in the first draft assumed possibility to access texture data in vertex shader. This may be prevented in some or most environments, so we can skip that...)

  • Option 3: Add the depth to vertex data

Do you need more than 1 sprite sheet? You can access 6 sheets with a cube map:

       |     |
       |     |
 |     |     |     |     |
 |     |     |     |     |
       |     |
       |     |

A cube has 6 faces and CUBE_MAP texture combines 6 individual sheets in a single texture. The texture coordinates are 3D and the face is selected by the dominant coordinate: if |x| > |y| && |x| > |z| then either 'left' or 'right' face is used. if |y| is the dominant coordinate, then top or bottom sheet is selected.

  • \$\begingroup\$ Wow.. awesome! That's completely clear to me now. Sorry for the trouble and thanks for taking the time to explain. \$\endgroup\$ Oct 29, 2012 at 17:47
  • \$\begingroup\$ How would one do this with actual sprites? If I for example have 2 sprites using the same spritesheet and frame, but requiring two different depths for the sprites? \$\endgroup\$ Apr 19, 2014 at 22:36

You must log in to answer this question.

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