PDA

View Full Version : Reverse Depth Buffer and gl_FragDepth

TheHighlander
04-25-2016, 03:03 PM
I just started using a reverse depth buffer. For some of my materials, I need to write to gl_FragDepth, but I can't seem to come up with the proper equation for gl_FragDepth with a reverse depth buffer.

The range of my reverse depth buffer is 1 to 0 instead of -1 to 1. I tried using

gl_FragDepth = ProjectionMatrix[3].z/vert_eye.z + ProjectionMatrix[2].z;

Has anyone had to deal with this before?

GClements
04-25-2016, 04:10 PM
I just started using a reverse depth buffer. For some of my materials, I need to write to gl_FragDepth, but I can't seem to come up with the proper equation for gl_FragDepth with a reverse depth buffer.
What do you mean by "reverse depth buffer"? You use glDepthRange(1,0)? Or the projection matrix was constructed to map Zd=near to +1 and Zd=far to -1? Or ... what?

Vertex positions written to gl_Position are in clip coordinates. Rasterisation interpolates these to generate a position in clip coordinates (Xc,Yc,Zc,Wc) for each fragment. Normalised device coordinates are obtained by dividing by W: Zd=Zc/Wc. This is then converted to window coordinates using either Zw=Zd*(f-n)/2+(f+n)/2 (for glClipControl(GL_NEGATIVE_ONE_TO_ONE), which is the default), or Zw=Zd*(f-n)+n (for glClipControl(GL_ZERO_TO_ONE)). The resulting Zd is the value of gl_FragCoord.z in the fragment shader, and is the value written to the depth buffer if the shader doesn't statically assign to gl_FragDepth.

If you're using a floating-point depth buffer and are mapping the far plane to a depth of zero so that the decreasing accuracy with increasing distance resulting from homogeneous division is counteracted by the increasing precision of floating-point representation closer to zero, then the reversal needs to be incorporated into the projection matrix. It can't be performed later, because the precision will have already been lost in the clip-space Z value.

TheHighlander
04-25-2016, 07:12 PM
Thanks for your response. I don't have the code in front of me, but by reverse depth I mean I modify the projection matrix and I call glClipControl( GL_ONE_TO_ZERO ). Thanks for your explanation of zd. I'll give it a shot tomorrow.

GClements
04-26-2016, 03:56 AM
I tried using

gl_FragDepth = ProjectionMatrix[3].z/vert_eye.z + ProjectionMatrix[2].z;

If eye-space Z is negative in front of the viewer (which is conventionally the case), the above is missing a negative sign;

Assuming that the bottom two rows of the projection matrix have the structure:

[ 0 0 A B]
[ 0 0 -1 0]

then

Zc = A*Ze + B
Wc = -Ze

Zd = Zc/Wc = -B/Ze - A

Zw = Zd*(f-n)+n

With the default glDepthRange setting, n=0 and f=1, so

Zw = Zd

For zero-to-one depth, the values A and B in the projection matrix should be:

A = near / (far - near)
B = far * near / (far - near)

Note that both of these will be positive (whereas negative-one-to-one depth has them both negative).

The far distance can be set to infinity, in which case 1/(far-near)=0 and far/(far-near)=1 => A=0 and B=near, and the equation for Zd simplifies to

Zd = -near / Ze

It should be clear that Zd = 1 when Ze = -near and Zd -> 0 as Ze -> -infinity.