I have an isometric scene in a custom engine where my world sim is 3D, but I'm rendering sprites. To depth sort, I follow the approach in this blog post. Basically: wrap each sprite in an AABB, then sort them by depth.

The condition it uses to test if one of the sprite's AABBs is behind another is:

if (b.minX < a.maxX && b.minY < a.maxY && b.minZ < a.maxZ)
    // b is behind a

however, this doesn't produce the result I would like in a few situations. Say I have two boxes, where one is intersecting the other: Separated boxes, and intersecting boxes

// BoundingBox is {minX, maxX, minY, maxY, minZ, maxZ}
BoundingBox spriteABounds{0, 7, 0, 32, 0, 78};
BoundingBox spriteBBounds{0, 32, 0, 32, 0, 78};

The desired behavior would be for sprite A to be behind sprite B, but the above condition considers both boxes to be behind eachother.

Another situation is when dealing with planes (note that the floor tile isn't graphically a plane, but should be treated as one in the world sim): Floor tile drawing over a wall

BoundingBox spriteABounds{0, 32, 0, 32, 78, 78};
BoundingBox spriteBBounds{32, 64, 0, 32, 0, 78};

The desired behavior would be for sprite A to be behind sprite B, but the above condition considers neither to be behind eachother.

Is there a way that I can set up the condition to handle these cases appropriately, or would I need to switch to a different approach? If the latter, what approach would be more appropriate?

  • \$\begingroup\$ Would be good to add illustrations in to the question. \$\endgroup\$
    – Kromster
    Commented May 21 at 13:55
  • \$\begingroup\$ Good point, added some images \$\endgroup\$
    – Archduke
    Commented May 21 at 18:24

1 Answer 1


Parallel projection

Isometric camera is represented as a flat plane, a parallel projection.

View plane

You can represent the camera plane as a point in 3D space and a (normalized) vector pointing into the scene (the normal of the view plane).

The view plane is viewPlane = { pos, norm } where pos is the 3D position of the camera in world space and norm is the 3D vector pointing into the scene in world space. (

Note You may have the camera's world matrix in which case norm is in the camera's world matrix (4by4) first 3 vals in 3rd row, and pos is the first 3 vals of the 4th row.

3D position and z distance

In the Iso view I assume your sprite is facing the camera, meaning that all pixels of the sprite will be equally distant from the cameras view plane. We can call this value zDist (distance from view plane)

The sprite has a 3D position sprite.pos Where pos is the 3D position in world space.

To get the zDist

// define alias for names
vP = viewPlane 
s = sprite 

d = vP.norm.x * vP.pos.x + vP.norm.y * vP.pos.y + vP.norm.z * vP.pos.z
s.zDist = vP.norm.x * s.pos.x + vP.norm.y * s.pos.y + vP.norm.z * s.pos.z - d 

// Optional if viewPlane.norm is NOT normalize do (div by norm length squared)
s.zDist /= vP.norm.x ** 2 + vP.norm.y ** 2 this.n.y + vP.norm.z ** 2

Note: That the normalization of the result s.zDist is not entirely necessary as you are only interested in relative distances. However I included the possible last step incase you use the zDist for fog like effects.

Note: Of the top of my head I can not remember the sign of sprite.zDist of above calculations. It is the distance from the sprite to the closest point on the view plane. If neg then sprite is behind view plane and not visible (if not swap sign)

Note: m ** n operator is m to power of n

Simple sort

If you have two sprites a, b

Check visible (in front of camera plane) a.zDist > 0. If not visible remove from sort list. (same for b)

When sorting sprites you need only sort on the zDist where if a.zDist < b.zDist a is in front of b

  • \$\begingroup\$ What point on the sprite's AABB should sprite.pos be? \$\endgroup\$
    – Archduke
    Commented May 21 at 18:57
  • \$\begingroup\$ @Archduke The center, but it does not matter where as long as its the same for all sprites. Do note that the sprites are a 2D representation of a 3D object and can not intersect in the z direction (they are flat and have no depth) and (I assume) your AABB boxes are 3D and can intersect. It is unclear if you want to sort 3D boxes and 2D sprite, or just 2D sprites. Why not just use the zbuffer and forgo the sort \$\endgroup\$
    – Blindman67
    Commented May 21 at 20:17
  • \$\begingroup\$ I have to do things this way because I'm using a 2D rendering interface (SDL2's native renderer) instead of using e.g. openGL where I have a zbuffer. To be clear though, I'm sorting 3D boxes and then rendering their associated sprites based on that sorting. \$\endgroup\$
    – Archduke
    Commented May 21 at 22:22
  • \$\begingroup\$ @Archduke Without a z (depth) buffer you can not correctly render intersecting faces (box has 6 faces) unless you manually slice intersecting faces to sort parts of each face as needed. This becomes very complex very quickly. Same with a sprite. it is either in front of a face or behind, it can not go through a face unless you cut the faces (and sprite) where they intercept and draw each part in sorted order. \$\endgroup\$
    – Blindman67
    Commented May 21 at 23:02
  • \$\begingroup\$ I don't need to slice any sprites, I recognize there will be certain instances where there's no way to render things correctly (e.g. three overlapping rectangular boxes), and I'm able to avoid those situations. I'm just looking for a way to make these two cases sort properly, particularly the first case, which should be doable. \$\endgroup\$
    – Archduke
    Commented May 21 at 23:24

You must log in to answer this question.

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