I read this article (https://developer.nvidia.com/content/depth-precision-visualized) about reverseZ and I'm confused about why is glClipControl necessary.Can't we juse modify ProjectionMatrix to make the depth in [0,1] and use glDepthRange(-1,1) to not do an extra (0.5* depth + 0.5) remapping before put it in the depth buffer? enter image description here


1 Answer 1


The screenshot you posted states the answer:

The value gets mapped into [0, 1] for storage in the depth buffer later, but that doesn't help, since the initial mapping to [-1, 1] has already destroyed all the precision in the far half of the range.

That [-1, 1] mapping cannot be changed by your projection matrix or anything else. It is a fundamental part of the OpenGL-defined fixed-function transformation sequence. It's the transformation from clip-coordinates to NDC coordinates. NDC coordinates range from [-1, 1] (without glClipControl).

Yes, you can use a projection matrix that maps the camera-space Z range to [1, 0] in NDC space. However, this creates two problems:

  1. This is done by using a clip space whose Z range is effectively [W, 0]. But OpenGL doesn't care what you think the range is; for GL, clip space is still [-W, W]. This means you will get no clipping in the [0, -W] parts of your scene. You can compensate for this by using a user-defined clip plane, but those aren't performance free.

  2. It doesn't actually fix the problem. The site you cited was written well after glClipControl, so it doesn't go into details for why this doesn't work. But this blog post was written beforehand, so it goes into those details.

    Because OpenGL still thinks the NDC space Z range is [-1, 1], it is going to map that space to [Rn, Rf] in the window-space transform, where Rn and Rf are the glDepthRange near and far values. So the transformation to window-space depth is this: you halve the NDC Z value, scale up by the difference between Rn and Rf... and then add half of that difference to get the window-space Z.

    And that addition is the problem. As stated on that site:

    That 0.5 bias locks the floating point exponent and pretty much destroys any and all additional precision that the encoding of floating point values brings close to zero, since now there are just 24 bits of mantissa to handle the unfortunate 1/z shape.

    That site suggests using a [-1, 1] depth range, but that's not allowed in unextended OpenGL. That's why it suggests glDepthRangeNV.

  • $\begingroup$ thanks for answering, great help.But when using glDepthRange(-1, 1) ,the mapping from ndc space to window space would be (1 - (-1)) * 0.5 * depth + (1 + -1),in which case the "add" operation wouldn't destroy the high precision near zero? $\endgroup$
    – Grown
    Sep 13, 2022 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.