How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
我阅读了许多有关使用片段着色器深入了解的信息。
如
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519
但是我仍然不知道
GLSL规范表示,其范围在屏幕空间中为[0,1],而未提及其是否为线性。
我认为线性度至关重要,因为我将使用渲染的模型来匹配Kinect的深度图。
那么,如果它不是线性的,如何在世界空间中线性化呢?
but I still don't know whether or not the gl_FragCoord.z is linear.
对于正交投影,
通常,深度(
1 2 | float ndc_depth = clip_space_pos.z / clip_space_pos.w; float depth = (((farZ-nearZ) * ndc_depth) + nearZ + farZ) / 2.0; |
投影矩阵描述了从场景的3D点到视口的2D点的映射。它从眼睛空间转换为剪辑空间,并且通过将剪辑坐标的w分量除以将剪辑空间中的坐标转换为归一化设备坐标(NDC)
正投影
在正交投影中,眼睛空间中的坐标线性映射到标准化设备坐标。
正射投影矩阵:
1 2 3 4 5 6 | 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 |
在正交投影中,Z分量由线性函数计算:
1 | z_ndc = z_eye * -2/(f-n) - (f+n)/(f-n) |
透视投影
在"透视投影"中,投影矩阵描述了从针孔相机看到的世界3D点到视口的2D点的映射。
摄像机视锥中的眼睛空间坐标(截断的金字塔)映射到立方体(规范化的设备坐标)。
透视投影矩阵:
1 2 3 4 5 6 | 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 |
在"透视投影"中,Z分量由有理函数计算:
1 | z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye |
深度缓冲
由于规范化的设备坐标在(-1,-1,-1)到(1,1,1)范围内,因此Z坐标必须映射到深度缓冲区[0,1]:
1 | depth = (z_ndc + 1) / 2 |
Then if it is not linear, how to linearize it in the world space?
要将深度缓冲区的深度转换为原始Z坐标,必须知道投影(正交或透视)以及近平面和远平面。
正投影
1 2 3 | n = near, f = far z_eye = depth * (f-n) + n; |
透视投影
1 2 3 4 | n = near, f = far z_ndc = 2.0 * depth - 1.0; z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n)); |
如果已知透视投影矩阵,则可以执行以下操作:
1 2 3 | A = prj_mat[2][2] B = prj_mat[3][2] z_eye = B / (A + z_ndc) |
另请参阅答案
如何在给定视图空间深度值和ndc xy的情况下恢复视图空间位置
一旦投影,它将失去线性,
要恢复为线性,您应该执行2个步骤:
1)将变量
1 | z = gl_FragCoord.z * 2.0 - 1.0 |
2)应用投影矩阵(IP)的逆矩阵。 (您可以对x和y使用任意值),并对最后一个分量进行规范化。
1 2 | unprojected = IP * vec4(0, 0, z, 1.0) unprojected /= unprojected.w |
您将在视图空间(或您称其为相机空间)中获得一个在znear和zfar之间具有线性z的点。
因此,当您的变换矩阵为
由您决定是否要线性Z,一切都取决于投影矩阵。您可以阅读以下内容:
http://www.songho.ca/opengl/gl_projectionmatrix.html
这很好地解释了投影矩阵的工作原理。非线性Z可能更好一些,以便在前景中具有更好的精度,而在背景中具有更少的精度,当距离较远时,深度伪影不太明显...