openGL何时以及如何计算F_depth(深度值)

When and how does openGL calculate F_depth(depth value)

意味着此时投影已经完成。这篇文章给了我们OpenGL使用的投影矩阵,影响一个点z坐标的因素是行:

[ 0 0 -(f+n)/(f-n) -2fn/(f-n) ]

注意,计算此矩阵是为了将“金字塔”平截头体变成一个单位立方体。这意味着应用此矩阵后 z 坐标也已映射到 [0,1]。

那么,作者在深度值精度章节告诉我们: 视图 space 中的这些 z 值可以是平截头体近平面和远平面之间的任何值,我们需要一些方法将它们转换为 [0,1]。 问题是为什么在这一点上,当我们在应用投影矩阵时已经映射了它。

另外,他说: 像这样的线性深度缓冲区: F_depth=z-near/(far-near) 从未使用过,为了正确的投影属性,使用了非线性深度方程:

F_depth= (1/z- 1/near)/(1/far - 1/near)

但是,正如我们所见,z 在范围内映射使用:

[ 0 0 -(f+n)/(f-n) -2fn/(f-n) ]

这似乎是线性的。

所有这些相互矛盾的陈述让我很困惑什么时候计算和比较片段的深度,以及实际用来计算这个的方程式是什么。在我的理解中,在应用 OpenGL 投影矩阵之后,不再需要计算深度,但是在阅读之后我真的很困惑。有任何说明吗?

perspective projection 处,深度不是线性的,因为存在透视差异。

当顶点坐标被投影矩阵转换后,剪辑 space 坐标被计算。剪辑 space 坐标是 Homogeneous coordinate. Now all the geometry which is not in clip space (in the Viewing frustum) 被剪辑。裁剪规则为:

-w <=  x, y, z  <= w

之后,通过将 xyz 分量除以 w 分量(Perspective divide). NDC are Cartesian coordinates 和归一化设备 space 是一个独特的立方体,左、下、近为 (-1, -1, -1) ,右、上、远为 (1, 1, 1)。所有立方体中的几何体投影在二维视口上。

注意,在齐次顶点坐标乘以透视投影矩阵(clip space)后,z 分量是“线性的”,但它不在 [-1, 1] 范围内。裁剪和透视划分后,z坐标在[-1, 1]范围内(NDC),但不再是“线性”。

深度缓冲区可以存储 [0, 1] 范围内的值。因此,标准化设备 space 的 z 分量必须从 [-1.0, 1.0] 映射到 [0.0, 1.0]。


在透视投影中,投影矩阵描述了从针孔相机看到的世界中的 3D 点到视口的 2D 点的映射。
相机视锥体(截棱锥)中的眼睛 space 坐标映射到立方体(归一化设备坐标)。

透视投影矩阵可以定义为frustum
距离 leftrightbottomtop 是近平面上从视图中心到平截头体侧面的距离。 nearfar 指定到平截头体近平面和远平面的距离。

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

x:    2*n/(r-l)      0              0                0
y:    0              2*n/(t-b)      0                0
z:    (r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1
t:    0              0              -2*f*n/(f-n)     0

如果投影是对称的,视线是平截头体的对称轴,矩阵可以简化:

a  = w / h
ta = tan( fov_y / 2 );

2 * n / (r-l) = 1 / (ta * a)
2 * n / (t-b) = 1 / ta
(r+l)/(r-l)   = 0
(t+b)/(t-b)   = 0

对称透视投影矩阵为:

x:    1/(ta*a)  0      0              0
y:    0         1/ta   0              0
z:    0         0     -(f+n)/(f-n)   -1
t:    0         0     -2*f*n/(f-n)    0

另见

What exactly are eye space coordinates?

How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?