如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

时间:2021-12-21 12:51:57

I read lots of information about getting depth with fragment shader.

我读了很多关于使用碎片着色器获得深度的信息。

such as

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

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

but I still don't know whether or not the gl_FragCoord.z is linear.

但是我仍然不知道gl_FragCoord是否。z是线性的。

GLSL specification said its range is [0,1] in screen sapce without mentioning it's linear or not.

GLSL规范说它的范围是[0,1]在屏幕上的sapce,但没有提到它是线性的还是非线性的。

I think linearity it is vital since I will use the rendered model to match depth map from Kinect.

我认为线性是非常重要的,因为我将使用渲染模型来匹配Kinect的深度地图。

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

那么如果它不是线性的,如何在世界空间中线性化它呢?

4 个解决方案

#1


11  

but I still don't know whether or not the gl_FragCoord.z is linear.

但是我仍然不知道gl_FragCoord是否。z是线性的。

Whether gl_FragCoord.z is linear or not depends on, the projection matrix. While for Orthographic Projection gl_FragCoord.z is linear, for Perspective Projection it is not linear.

是否gl_FragCoord。z是否线性取决于投影矩阵。而对于正射投影gl_FragCoord。z是线性的,对于透视投影它不是线性的。

In general, the depth (gl_FragCoord.z and gl_FragDepth) is calculated as follows (see GLSL gl_FragCoord.z Calculation and Setting gl_FragDepth):

一般来说,深度(gl_FragCoord)。z和gl_FragDepth)的计算方法如下(参见GLSL gl_FragCoord)。z计算和设置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 3D points of a scene, to 2D points of the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates

投影矩阵描述从场景的3D点到视图端口的2D点的映射。它从人眼空间转换到剪贴空间,剪贴空间中的坐标通过与剪贴坐标的w分量进行划分,转换为归一化设备坐标(NDC)

Orthographic Projection

At Orthographic Projection the coordinates in the eye space are linearly mapped to normalized device coordinates.

在正投影中,眼睛空间中的坐标被线性映射到归一化的设备坐标。

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Orthographic Projection Matrix:

正射投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2/(r-l)         0               0               0
0               2/(t-b)         0               0
0               0               -2/(f-n)        0
-(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1

At Orthographic Projection, the Z component is calcualted by the linear function:

在正射投影中,Z分量由线性函数计算:

z_ndc = z_eye * -2/(f-n) - (f+n)/(f-n)

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Perspective Projection

At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).

在透视投影中,投影矩阵描述了从一个针孔相机到视点的二维点,从世界的三维点到三维点的映射。摄像机截锥中的眼睛空间坐标被映射到一个立方体(归一化的设备坐标)。

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Perspective Projection Matrix:

透视投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

At Perspective Projection, the Z component is calcualted by the rational function:

在透视投影中,Z分量由有理函数计算:

z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Depth buffer

Since the normalized device coordinates are in range (-1,-1,-1) to (1,1,1) the Z-coordinate has to be mapped to the depth buffern the range [0,1]:

由于归一化设备坐标在(- 1,1,-1)到(1,1)的范围内,z坐标必须映射到深度缓冲范围[0,1]:

depth = (z_ndc + 1) / 2 


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

那么如果它不是线性的,如何在世界空间中线性化它呢?

To convert form the depth of the depth buffer to the original Z-coordinate, the projection (Orthographic or Perspective), and the near plane and far plane has to be known.

要将深度缓冲区的深度转换为原来的z坐标、投影(正投影或透视)、*面和远平面,必须知道。

Orthographic Projection

正射投影

n = near, f = far

z_eye = depth * (f-n) + 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 the answer to

请参阅答案

How to recover view space position given view space depth value and ndc xy

如何在给定的视图空间深度值和ndc xy的情况下恢复视图空间位置

#2


6  

Once it's projected it loses its linearity, gl_FragCoord.z is not linear.

一旦投影,它就失去了线性,gl_FragCoord。z不是线性的。

To revert back to linear you should perform 2 steps:

要恢复到线性,你应该执行两个步骤:

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

1)转换变量gl_FragCoord。z到范围内的归一化设备坐标[- 1,1]

z = gl_FragCoord.z * 2.0 - 1.0 

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

2)应用投影矩阵的逆(IP)。(可以为x和y使用任意值),并对最后一个组件进行规范化。

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

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

你将在视图空间(或相机空间,你可以命名它)中获得一个在znear和zfar之间有一个线性z的点。

#3


2  

Its up to you to decide if you want linear Z or not, everythings relies on your projection matrix. You may read this:

这取决于你是否想要线性Z,所有的一切都依赖于你的投影矩阵。你可以阅读这个:

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

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

Which explains very well how projection matrices works. It may be better to have non-linear Z in order to have better precision in the foreground and less in the backgrounds, depth artifacts are less visible when far away...

这很好地解释了投影矩阵的工作原理。最好是使用非线性Z,以便在前景中有更好的精度,而在背景中,深度工件在很远的地方是不可见的……

#4


1  

Whether gl_FragCoord.z is linear or not depends on your transformation matrix. gl_FragCoord.z is determined by computing gl_Position.z / gl_Position.w for all vertices of your triangle and then interpolating the result over all fragments of that triangle.

是否gl_FragCoord。z是否线性取决于你的变换矩阵。gl_FragCoord。z是由计算gl_Position决定的。z / gl_Position。w表示三角形的所有顶点然后在三角形的所有碎片上插入结果。

So gl_FragCoord.z is linear when your transformation 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 coordinate of your input vector (which happens with perspective projection matrices).

所以gl_FragCoord。当变换矩阵将一个常数值赋给gl_Position时,z是线性的。w(通常发生在正交投影矩阵中),在gl_Position中是非线性的。w取决于输入向量的x、y或z坐标(在透视投影矩阵中发生)。

#1


11  

but I still don't know whether or not the gl_FragCoord.z is linear.

但是我仍然不知道gl_FragCoord是否。z是线性的。

Whether gl_FragCoord.z is linear or not depends on, the projection matrix. While for Orthographic Projection gl_FragCoord.z is linear, for Perspective Projection it is not linear.

是否gl_FragCoord。z是否线性取决于投影矩阵。而对于正射投影gl_FragCoord。z是线性的,对于透视投影它不是线性的。

In general, the depth (gl_FragCoord.z and gl_FragDepth) is calculated as follows (see GLSL gl_FragCoord.z Calculation and Setting gl_FragDepth):

一般来说,深度(gl_FragCoord)。z和gl_FragDepth)的计算方法如下(参见GLSL gl_FragCoord)。z计算和设置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 3D points of a scene, to 2D points of the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates

投影矩阵描述从场景的3D点到视图端口的2D点的映射。它从人眼空间转换到剪贴空间,剪贴空间中的坐标通过与剪贴坐标的w分量进行划分,转换为归一化设备坐标(NDC)

Orthographic Projection

At Orthographic Projection the coordinates in the eye space are linearly mapped to normalized device coordinates.

在正投影中,眼睛空间中的坐标被线性映射到归一化的设备坐标。

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Orthographic Projection Matrix:

正射投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far 

2/(r-l)         0               0               0
0               2/(t-b)         0               0
0               0               -2/(f-n)        0
-(r+l)/(r-l)    -(t+b)/(t-b)    -(f+n)/(f-n)    1

At Orthographic Projection, the Z component is calcualted by the linear function:

在正射投影中,Z分量由线性函数计算:

z_ndc = z_eye * -2/(f-n) - (f+n)/(f-n)

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Perspective Projection

At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).

在透视投影中,投影矩阵描述了从一个针孔相机到视点的二维点,从世界的三维点到三维点的映射。摄像机截锥中的眼睛空间坐标被映射到一个立方体(归一化的设备坐标)。

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Perspective Projection Matrix:

透视投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

At Perspective Projection, the Z component is calcualted by the rational function:

在透视投影中,Z分量由有理函数计算:

z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye

如何用gl_FragCoord在现代OpenGL中线性渲染深度。z在片段着色器吗?

Depth buffer

Since the normalized device coordinates are in range (-1,-1,-1) to (1,1,1) the Z-coordinate has to be mapped to the depth buffern the range [0,1]:

由于归一化设备坐标在(- 1,1,-1)到(1,1)的范围内,z坐标必须映射到深度缓冲范围[0,1]:

depth = (z_ndc + 1) / 2 


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

那么如果它不是线性的,如何在世界空间中线性化它呢?

To convert form the depth of the depth buffer to the original Z-coordinate, the projection (Orthographic or Perspective), and the near plane and far plane has to be known.

要将深度缓冲区的深度转换为原来的z坐标、投影(正投影或透视)、*面和远平面,必须知道。

Orthographic Projection

正射投影

n = near, f = far

z_eye = depth * (f-n) + 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 the answer to

请参阅答案

How to recover view space position given view space depth value and ndc xy

如何在给定的视图空间深度值和ndc xy的情况下恢复视图空间位置

#2


6  

Once it's projected it loses its linearity, gl_FragCoord.z is not linear.

一旦投影,它就失去了线性,gl_FragCoord。z不是线性的。

To revert back to linear you should perform 2 steps:

要恢复到线性,你应该执行两个步骤:

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

1)转换变量gl_FragCoord。z到范围内的归一化设备坐标[- 1,1]

z = gl_FragCoord.z * 2.0 - 1.0 

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

2)应用投影矩阵的逆(IP)。(可以为x和y使用任意值),并对最后一个组件进行规范化。

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

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

你将在视图空间(或相机空间,你可以命名它)中获得一个在znear和zfar之间有一个线性z的点。

#3


2  

Its up to you to decide if you want linear Z or not, everythings relies on your projection matrix. You may read this:

这取决于你是否想要线性Z,所有的一切都依赖于你的投影矩阵。你可以阅读这个:

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

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

Which explains very well how projection matrices works. It may be better to have non-linear Z in order to have better precision in the foreground and less in the backgrounds, depth artifacts are less visible when far away...

这很好地解释了投影矩阵的工作原理。最好是使用非线性Z,以便在前景中有更好的精度,而在背景中,深度工件在很远的地方是不可见的……

#4


1  

Whether gl_FragCoord.z is linear or not depends on your transformation matrix. gl_FragCoord.z is determined by computing gl_Position.z / gl_Position.w for all vertices of your triangle and then interpolating the result over all fragments of that triangle.

是否gl_FragCoord。z是否线性取决于你的变换矩阵。gl_FragCoord。z是由计算gl_Position决定的。z / gl_Position。w表示三角形的所有顶点然后在三角形的所有碎片上插入结果。

So gl_FragCoord.z is linear when your transformation 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 coordinate of your input vector (which happens with perspective projection matrices).

所以gl_FragCoord。当变换矩阵将一个常数值赋给gl_Position时,z是线性的。w(通常发生在正交投影矩阵中),在gl_Position中是非线性的。w取决于输入向量的x、y或z坐标(在透视投影矩阵中发生)。