OpenGL gotcha: depth buffer distortion

While I’m on the topic of OpenGL gotchas, I thought I’d mention another which caught me out a couple of years ago. I was working on some prototypes with some friends, and you can see a screenshot on the right (click it for a full view).

Notice areas where polygons overlap — you can see a striped or checked pattern of the occluded polygon showing through. In this case, it was 2d graphics and a 3d camera (so that we could make some interested visual effects). However, the problem manifests just as badly in full 3d.

It took quite a while to figure out the problem, and it’s one I’ll never forget.

You would be forgiven for thinking any of the following were at fault:

  • Polygons are too close together
  • Depth equation is incorrect
  • Depth buffer is too small (not enough bits)
  • Near and far clipping planes are too far apart

As it turns out, the near clipping was a little too near. If you want to see this for yourself, just try modifying existing code to put the near clipping plane at 0, and watch the depth buffer squirm!

Why does this happen?

When your scene is going to be rendered, all the geometry gets passed through the various coordinate spaces, until it is mapped nicely into your viewing frustum. The frustum is effectively squished into a nice orthogonal cuboid, with your rendering viewport being one side of it.

At this point, viewport dimensions are mapped onto the X and Y (horizontal and vertical) axes — that could be your screen resolution, for example. Meanwhile, the depth buffer is mapped onto the Z axis. The depth buffer size is usually determined when initialising OpenGL, and could be 24 bits. That would mean you could hypothetically represent around 16.7 million different depths in between your near and far clipping planes.

You might expect the depth buffer to be uniformly mapped along the Z axis of this viewing box. However, the usual mapping increases as you approach the camera. This is to allow for more detailed depth handling for polygons which are visibly ‘nearer’ the viewport (and therefore more noticeable).

As a result, if your near clipping is at (or very very near) a depth of 0, then your depth buffer mapping is almost entirely clustered at that depth. In other words, you end with very few bits (if any) left for the rest of your viewing frustum. The ultimate consequence is such low precision depth representation that it looks like your depth buffer is being distorted or corrupted.

Remember kids: just say “no” to near clipping planes at 0 depth. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *