如何在片段着色器中使用gl_FragCoord.z在现代OpenGL中呈现线性深度?

我阅读了大量有关使用片段着色器获得深度的信息。

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

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

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

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

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

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

投影matrix是否取决于gl_FragCoord.z是否是线性的。 而对于正交投影gl_FragCoord.z是线性的,对于透视投影它不是线性的。

通常,深度( gl_FragCoord.zgl_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; 

投影matrix描述了从场景的3D点到视口的2D点的映射。 它从眼睛空间转换到剪辑空间,剪辑空间中的坐标通过除以剪辑坐标的w分量而转换为标准化设备坐标(NDC)

正投影

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

正投影

正交投影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 

在正交投影中,Z分量由线性函数进行计算

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

正交Z函数

透视投影

在透视投影中,投影matrix描述从针孔摄像机看到的世界中的3D点到视区的2D点的映射。
摄像机视锥体(截断的金字塔)中的眼睛空间坐标被映射到立方体(标准化的设备坐标)。

透视投影

透视投影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 

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

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

透视Z功能

深度缓冲区

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

 depth = (z_ndc + 1) / 2 

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

为了将深度caching的深度转换为原始的Z坐标,必须知道投影(正交或透视)以及近平面和远平面。

正投影

 n = near, f = far z_eye = depth * (fn) + n; 

透视投影

 n = near, f = far z_ndc = 2.0 * depth - 1.0; z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n)); 

如果透视投影matrix已知,则可以如下进行:

 A = prj_mat[2][2] B = prj_mat[3][2] z_eye = B / (A + z_ndc) 

另见答案

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

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

要恢复到线性,您应执行2个步骤:

1)将variablesgl_FragCoord.z转换为范围为[-1,1]的标准化设备坐标

 z = gl_FragCoord.z * 2.0 - 1.0 

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

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

您将获得在znear和zfar之间具有线性z的视图空间(或相机空间,您将其命名)。

它取决于你决定是否你想要线性Z,万物依赖于你的投影matrix。 你可以阅读这个:

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

这很好地解释了投影matrix的工作原理。 为了在前景中具有更好的精度和较less的背景,可能会有更好的非线性Z值,深度伪影在远处时不太明显。

gl_FragCoord.z是否是线性取决于您的变换matrix。 gl_FragCoord.z是通过为三angular形的所有顶点计算gl_Position.z / gl_Position.w来确定的,然后在三angular形的所有片段上插入结果。

因此, gl_FragCoord.z是线性的,当你的变换matrix给gl_Position.w (通常发生在正投影matrix上)发生一个常量值时, gl_Position.w取决于input向量的xyz坐标,它是非线性的(这与透视投影matrix发生)。