How to visualize depth linearly in modern OpenGL with gl_FragCoord.z โ€‹โ€‹in a flash shader?

I read a lot of information about getting depth using the fragment shader.

such as

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519

but I still don't know if the ruler is gl_FragCoord.z .

The GLSL specification stated that its range is [0.1] in the screen sax, not mentioning it linear or not.

I think linearity is vital since I will use a visualized model to map a depth map to Kinect.

Then, if it is not linear, how to linearize it in world space?

+6
source share
4 answers

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.

Spelling projection

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) 

Spelling Function Z

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).

Perspective projection

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 

Perspective function z

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

+10
source

After projecting, it loses its linearity, gl_FragCoord.z not linear.

To return to linear, you have to follow 2 steps:

1) Convert the gl_FragCoord.z variable to normalized device coordinates in the range [-1, 1]

 z = gl_FragCoord.z * 2.0 - 1.0 

2) Apply inverse projection matrix (IP). (You can use arbitrary values โ€‹โ€‹for x and y) and normalize for the last component.

 unprojected = IP * vec4(0, 0, z, 1.0) unprojected /= unprojected.w 

you get a point in view space (or camera space, you name it) that has a linear z between znear and zfar.

+7
source

To decide whether you want linear Z or not, it all depends on your projection matrix. You can read this:

http://www.songho.ca/opengl/gl_projectionmatrix.html

This explains very well how projection matrices work. It is better to have a non-linear Z in order to have better accuracy in the foreground and less in the background, depth artifacts are less noticeable when far ...

+2
source

Whether gl_FragCoord.z is linear or independent of your transformation matrix . gl_FragCoord.z determined by calculating gl_Position.z / gl_Position.w for all the vertices of your triangle, and then interpolating the result across all fragments of this triangle.

So gl_FragCoord.z is linear when your transform matrix assigns a constant value to gl_Position.w (which usually happens with ortho projection matrices) and is non-linear when gl_Position.w depends on the x , y or z coordinates of your input vector (which happens with projection matrices of perspective ).

+1
source

Source: https://habr.com/ru/post/899357/


All Articles