but I still don't know if gl_FragCoord.z โโis linear.
Whether gl_FragCoord.z
linear or independent of the projection matrix. Although gl_FragCoord.z
is linear for the orthographic projection, gl_FragCoord.z
is not linear for the Perspective projection.
In general, the depth ( gl_FragCoord.z
and gl_FragDepth
) is calculated as follows (see GLSL gl_FragCoord.z โโCalculation and adjustment of gl_FragDepth ):
float ndc_depth = clip_space_pos.z / clip_space_pos.w; float depth = (((farZ-nearZ) * ndc_depth) + nearZ + farZ) / 2.0;
The projection matrix describes the mapping from three-dimensional points of the scene to two-dimensional points of the viewport. It is transformed from the eye space to the clip space, and the coordinates in the clip space are converted to normalized device coordinates (NDC) by dividing the clip coordinates by the w-component
Spelling projection
In the orthographic projection, the coordinates in the eye space are linearly mapped to the normalized coordinates of the device.
Orthographic projection matrix:
r = right, l = left, b = bottom, t = top, n = near, f = far 2/(rl) 0 0 0 0 2/(tb) 0 0 0 0 -2/(fn) 0 -(r+l)/(rl) -(t+b)/(tb) -(f+n)/(fn) 1
In the orthographic projection, the Z component is calculated using a linear function :
z_ndc = z_eye * -2/(fn) - (f+n)/(fn)
Perspective projection
In a perspective projection, the projection matrix describes the mapping from three-dimensional points in the world, as they are visible from a pinhole camera, to the 2D points of the viewport. The coordinates of the eye space in the truncation of the camera (truncated pyramid) are displayed in a cube (coordinates of the normalized device).
Projected Projection Matrix:
r = right, l = left, b = bottom, t = top, n = near, f = far 2*n/(rl) 0 0 0 0 2*n/(tb) 0 0 (r+l)/(rl) (t+b)/(tb) -(f+n)/(fn) -1 0 0 -2*f*n/(fn) 0
In the Perspective Projection, the components of Z are calculated using a rational function :
z_ndc = ( -z_eye * (f+n)/(fn) - 2*f*n/(fn) ) / -z_eye
Depth buffer
Since the normalized coordinates of the device are in the range (-1, -1, -1) to (1,1,1), the Z-coordinate should be mapped to the depth of the range buffer [0,1]:
depth = (z_ndc + 1) / 2
Then, if it is not linear, how to linearize it in world space?
To convert the depth shape of the depth buffer to the original Z-coordinate, the projection (orthographic or perspective), as well as the near and far planes, must be known.
Spelling projection
n = near, f = far z_eye = depth * (fn) + n;
Perspective projection
n = near, f = far z_ndc = 2.0 * depth - 1.0; z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
If the perspective projection matrix is โโknown, this can be done as follows:
A = prj_mat[2][2] B = prj_mat[3][2] z_eye = B / (A + z_ndc)
See also answer to
How to restore the position of the representation space of a given value of the depth of the viewing space and ndc xy