如何在片段着色器中使用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.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;
投影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)
透视投影
在透视投影中,投影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
深度缓冲区
由于归一化的设备坐标在(-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向量的x
, y
或z
坐标,它是非线性的(这与透视投影matrix发生)。