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.
Three questions:
- Why add
gl_DepthRange.far
to the calculation? - Why divide by 2?
- I set the
pv
matrix in C++ withglm::perspective(...)*glm::lookAt(...)
so how the hell doesgl_DepthRange
know what the near and far planes are?