美文网首页
深度缓冲中的深度值计算及可视化

深度缓冲中的深度值计算及可视化

作者: bzyzhang | 来源:发表于2020-04-09 16:50 被阅读0次

概述

渲染管线中的顶点变换中,介绍了顶点在各个坐标空间的变换。变换到最后,是屏幕坐标空间。在OpenGL中,屏幕空间坐标的Z值即是深度缓冲中的深度值。深度缓冲包含了一个介于0.0和1.0之间的深度值,它将会与观察者视角所看见的场景中所有物体的z值进行比较。本文将介绍深度值的计算,以及从深度值反向计算出相机空间中的顶点的Z值。

深度值计算

渲染管线中的顶点变换中,计算得到了透视投影矩阵:
M_{persp} = \begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{l+r}{l-r} & 0 \\ 0 & \frac{2n}{t-b} & \frac{b+t}{b-t} & 0 \\ 0 & 0 & \frac{f+n}{f-n} & \frac{2nf}{n-f} \\ 0 & 0 & 1 & 0 \\ \end{bmatrix}
同时,也得到了视口变换矩阵:
M_{viewport} = \begin{bmatrix} \frac{w}{2} & 0 & 0 & \frac{w}{2} \\ 0 & \frac{h}{2} & 0 & \frac{h}{2} \\ 0 & 0 & \frac{1}{2} & \frac{1}{2} \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}
首先,根据透视矩阵,计算NDC空间的Z值。这里,相机空间中的坐标经过透视矩阵变换后,还要进行齐次除法,才能得到NDC空间中的坐标。
\begin{pmatrix} x_{clip} \\ y_{clip} \\ z_{clip} \\ w_{clip} \\ \end{pmatrix} = M_{persp} \begin{pmatrix} x_{eye} \\ y_{eye} \\ z_{eye} \\ w_{eye} \\ \end{pmatrix}

\begin{pmatrix} x_{ndc} \\ y_{ndc} \\ z_{ndc} \\ \end{pmatrix} = \begin{pmatrix} \frac{x_{clip}}{w_{clip}} \\ \frac{y_{clip}}{w_{clip}} \\ \frac{z_{clip}}{w_{clip}} \\ \end{pmatrix}

由此,可以得出:
\begin{aligned} z_{ndc} &= \frac{\frac{f+n}{f-n}z_{eye}+\frac{-2nf}{f-n}}{z_{eye}} \\ &=\frac{f+n}{f-n}+\frac{-2nf}{z_{eye}(f-n)} \end{aligned} \tag{1}
根据上述公式,可以得出:
z_{eye} = \frac{2nf}{(f+n)-z_{ndc}(f-n)} \tag{2}
根据视口变换矩阵,可以得出:
z_{win} = \frac{1}{2}z_{ndc}+\frac{1}{2} \tag{3}

\left(1\right)带入\left(3\right),可以得到:
\begin{aligned} z_{win} &= \frac{1}{2}(z_{ndc}+1) \\ &=\frac{1}{2}(\frac{f+n}{f-n}+\frac{-2nf}{z_{eye}(f-n)} + 1) \\ &=\frac{f-\frac{nf}{z_{eye}}}{f-n} \\ &= \frac{\frac{1}{n}-\frac{1}{z_{eye}}}{\frac{1}{n}-\frac{1}{f}} \end{aligned}

即:
z_{win} = \frac{\frac{1}{n}-\frac{1}{z_{eye}}}{\frac{1}{n}-\frac{1}{f}} \tag{4}

到这一步,即可以求得屏幕空间中的深度。

Learn OpenGL CN学习过的,可能对深度测试这一节的内容有些印象。它得到的深度值的公式是:
F_{depth} = \frac{1/z - 1/near}{1/far - 1/near}
\left(4\right)式对比,发现有些不一样,这是怎么回事呢?

这里要注意,本文定义的nfz_{eye}是实际的坐标值,是负的。而深度测试文中,定义的nearfar代表了近平面和远平面,而z代表了近、远平面之间的值,它们都是正的。将n=-nearf=-farz_{eye}=-z代入\left(4\right)式,可得:
\begin{aligned} F_{depth} &= z_{win} \\ &= \frac{\frac{1}{n}-\frac{1}{z_{eye}}}{\frac{1}{n}-\frac{1}{f}} \\ &= \frac{\frac{1}{-near}-\frac{1}{-z}}{\frac{1}{-near}-\frac{1}{-far}} \\ &= \frac{\frac{1}{z}-\frac{1}{near}}{\frac{1}{far}-\frac{1}{near}} \end{aligned}

深度值的线性可视化

经过上面的推导,我们得出了深度值的计算公式。

现在,反过来,我们知道了屏幕空间中的深度值,怎么求出相机空间中的深度值呢?

首先,根据\left(3\right),可以推导出:
z_{ndc} = 2z_{win}-1
对于公式2,得出的是实际坐标的Z值。为了和OpenGL中的定义统一,也将nearfarz代入公式\left(2\right),可以得到:
\begin{aligned} z_{eye} &= \frac{2(-near)(-far)}{((-far)+(-near))-z_{ndc}((-far)-(-near))} \\ &= \frac{2nearfar}{-(far+near)-z_{ndc}(near-far)} \\ \end{aligned} \tag{5}
深度测试这一节中,得出的公式是:
float \quad linearDepth = (2.0 * near * far) / (far + near - z * (far - near));
对比发现,跟公式\left(5\right)有些不一样。这是因为,linearDepth求出的是顶点距离相机的距离,是正值。而z_{eye}是顶点的实际坐标,是负值,将z_{eye}取反,即可得到linearDepth
\begin{aligned} linearDepth &= -z_{eye} \\ &= \frac{2nearfar}{(far+near)-z_{ndc}(far-near)} \end{aligned}
至此,推导完成。

参考

相关文章

  • OpenGL-深度测试

    本节了解的内容 什么叫做深度缓冲区。 深度缓冲区的作用。 如何使用深度缓冲区测试。 可视化深度值。 如何解决深度值...

  • 深度缓冲中的深度值计算及可视化

    概述 在渲染管线中的顶点变换中,介绍了顶点在各个坐标空间的变换。变换到最后,是屏幕坐标空间。在OpenGL中,屏幕...

  • OpenGL-深度测试

    通过本文你可以了解到的 什么是深度? 什么是深度缓缓冲区? 如何使用深度测试? 什么是可视化深度值? 深度值相同如...

  • OpenGL 基础渲染(颜色混合)

    OpenGL 混合 OpenGL渲染时会把颜色值存在颜色缓存区中,每个片段的深度值也是放在深度缓冲区。当深度缓冲区...

  • 四.OpenGL 颜色混合

    我们把OpenGL 渲染时会把颜⾊值存在颜色缓存区中,每个片段的深度值也是放在深度缓冲区。当深度 缓冲区被关闭时,...

  • OpenGL颜色混合

    OpenGL 渲染时会把颜⾊值存在颜⾊缓存区中,每个⽚元的深度值也是放在深度缓冲区。当深度缓冲区被关闭时,新的颜⾊...

  • 3.5 颜色混合

    我们把OpenGL渲染时会把颜⾊色值存在颜⾊缓存区中,每个片段的深度值也是放在深度缓冲区。当深度 缓冲区被关闭时,...

  • OpenGL 颜色混合

    我们把OpenGL 渲染时会把颜⾊值存在颜⾊缓存区中,每个⽚段的深度值也是放在深度缓冲区。当深度缓冲区被关闭时,新...

  • OpenGL-颜色混合

    在一般情况下,OpenGL在渲染时把颜色值存放在颜色缓冲区中,把每个片段(像素)的深度值存放在深度缓冲区中。当深度...

  • 深度/模板测试

    深度测试 深度缓冲(Depth Buffer)存储每个片段的信息,深度缓冲由窗口系统自动创建并将其深度值存储为 1...

网友评论

      本文标题:深度缓冲中的深度值计算及可视化

      本文链接:https://www.haomeiwen.com/subject/roncmhtx.html