tom*_*234 9 opengl shader glsl depth-buffer depth
我阅读了很多关于使用片段着色器获取深度的信息.
如
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=234519
但我还是不知道这是否gl_FragCoord.z是线性的.
GLSL规范称屏幕上的范围为[0,1]而未提及线性与否.
我认为线性是至关重要的,因为我将使用渲染模型来匹配Kinect的深度图.
那么如果它不是线性的,那么如何在世界空间中线性化呢?
Rab*_*d76 23
但我还是不知道gl_FragCoord.z是否是线性的.
是否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;
Run Code Online (Sandbox Code Playgroud)
投影矩阵描述了从场景的3D点到视口的2D点的映射.它从眼睛空间转换到剪辑空间,并通过用剪辑坐标的w分量进行划分,将剪辑空间中的坐标转换为规范化设备坐标(NDC)
在正交投影中,眼睛空间中的坐标线性映射到标准化设备坐标.
正投影矩阵:
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
Run Code Online (Sandbox Code Playgroud)
在正交投影中,Z分量由线性函数计算:
z_ndc = z_eye * -2/(f-n) - (f+n)/(f-n)
Run Code Online (Sandbox Code Playgroud)
在透视投影中,投影矩阵描述了从针孔相机到视口的2D点看世界中3D点的映射.
相机平截头体(截头金字塔)中的眼睛空间坐标被映射到立方体(标准化设备坐标).
透视投影矩阵:
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
Run Code Online (Sandbox Code Playgroud)
在Perspective Projection中,Z分量由有理函数计算:
z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye
Run Code Online (Sandbox Code Playgroud)
由于归一化设备坐标在范围(-1,-1,-1)到(1,1,1)范围内,因此Z坐标必须映射到范围[0,1]的深度缓冲区:
depth = (z_ndc + 1) / 2
Run Code Online (Sandbox Code Playgroud)
那么如果它不是线性的,如何在世界空间中线性化它呢?
要将深度缓冲区的深度转换为原始Z坐标,必须知道投影(正交或透视)以及近平面和远平面.
正投影
n = near, f = far
z_eye = depth * (f-n) + n;
Run Code Online (Sandbox Code Playgroud)
透视投影
n = near, f = far
z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
Run Code Online (Sandbox Code Playgroud)
如果透视投影矩阵已知,则可以按如下方式完成:
A = prj_mat[2][2]
B = prj_mat[3][2]
z_eye = B / (A + z_ndc)
Run Code Online (Sandbox Code Playgroud)
另见答案
如何在给定视图空间深度值和ndc xy的情况下恢复视图空间位置
pyg*_*iel 10
一旦它被预测它失去线性,gl_FragCoord.z不是线性的.
要恢复为线性,您应该执行两个步骤:
1)将变量转换为gl_FragCoord.z[-1,1]范围内的标准化设备坐标
z = gl_FragCoord.z * 2.0 - 1.0
Run Code Online (Sandbox Code Playgroud)
2)应用投影矩阵(IP)的逆.(您可以对x和y使用任意值),并对最后一个组件进行标准化.
unprojected = IP * vec4(0, 0, z, 1.0)
unprojected /= unprojected.w
Run Code Online (Sandbox Code Playgroud)
您将获得在znear和zfar之间具有线性z的视图空间(或相机空间,您可以命名)中的点.
由您决定是否需要线性 Z,一切都取决于您的投影矩阵。您可以阅读以下内容:
http://www.songho.ca/opengl/gl_projectionmatrix.html
这很好地解释了投影矩阵的工作原理。最好使用非线性 Z,以便在前景中获得更好的精度,在背景中获得更少的精度,当距离很远时,深度伪像不太明显......
| 归档时间: |
|
| 查看次数: |
9822 次 |
| 最近记录: |