I am raytracing in GLSL. My
gl_FragDepth calculation wasn't right, so I did some hunting and found this solution (
P is the world-space coordinate of the pixel and
pv is proj*view):
vec4 Pclip = pv * vec4 (P, 1); float ndc_depth = Pclip.z / Pclip.w; gl_FragDepth = ( (gl_DepthRange.diff * ndc_depth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;
It works. But why?
Okay, so I need to divide by
w and scale it to the expected z-range. That makes sense qualitatively, but the calculation surprised me.
If you told me to "divide by
w and scale to
gl_DepthRange" I would have written
float ndc_depth = Pclip.z / Pclip.w; gl_FragDepth = gl_DepthRange.diff * ndc_depth + glDepthRange.near;
At this point I'd like to point out that this depth calculation looks correct with the raytraced geometry which is intersecting with my normal triangle models, so I guess OpenGL is performing the same depth-scaling implicitly for those triangles as well.
- Why add
gl_DepthRange.farto the calculation?
- Why divide by 2?
- I set the
pvmatrix in C++ with
glm::perspective(...)*glm::lookAt(...)so how the hell does
gl_DepthRangeknow what the near and far planes are?