我正在学习3D计算机图形学,但是很难理解为什么不能将视锥的近平面放置在z位置$ 0 $(在相机处)。

我可以从概念上理解近平面本质上是视网膜画布-因此从定义上说它必须存在一定程度-但我很难理解为什么近平面不是简单的抽象概念,它的实际位置无限地接近于

在几个解释中,给出以下公式来解释为什么不能将$ 0 $用作附近计划位置(其中$ A $是相机位置,$ B $是对象顶点,$ D $是点$ B $在近平面上的透视投影):



$$ { BC \ over AC} = {DE \ over AE} $$

在这种情况下,相似三角形$ ABC $和$ ADE $的几何形状用于确定$ D $的高度$ DE的解决方案$。显然,如果近平面位于$ 0 $($ AE = 0 $)处,则将被$ 0 $除以-因此,为什么近平面无法位于位置$ 0 $。 >但是,为什么使用这种方法确定$ D $在画布上的位置?

我之前编写了一个简单的光线投射可视化器,但没有明确定义的近平面。在我的引擎中,我仅定义了一个$ 60 ^ \ circ $视场,并将屏幕上的像素数划分为该视场。例如,对于$ 300 $ x $ 300 $屏幕:

$$ 1 \ text {pixel} = 300/60 ^ \ circ = 5 ^ \ circ $$

下一个,我找到了相机和对象顶点之间的角度($ \ angle BAC $),然后将其除以$ 5 ^ \ circ $,以获取屏幕上的像素坐标。在这种方法中,不需要显式的近平面,而是使用我的实际相机位置确定角度。 br />

评论

近平面和远平面的一个关键点是它们设置深度在整个平面之间的变化方式。

#1 楼

对于简单的3D→2D投影,不需要视锥的近平面和远平面。在典型的光栅化器设置中,近平面和远平面实际执行的操作是定义深度缓冲区的值范围。

[near,far]范围内的深度将映射到[0,1]中以存储在深度缓冲区中。但是,深度并不是简单地线性缩放。取而代之的是,我们对深度使用双曲线映射:深度缓冲区中存储的值是实际深度距离的倒数,并应用了比例和偏移。



如果您看这条曲线并想象将近平面值移向$ z = 0 $,则$ 1 / z $曲线上的对应点将朝无穷远方向射击。数学崩溃,深度缓冲区变得无用(它遭受了灾难性的精度损失)。

之所以使用倒数而不是其他深度函数,基本上是很方便的:倒数深度插值非常适合在屏幕空间中使用,并且很自然地适合透视投影的数学框架:$ z $除法已应用于$ x,y $坐标。

如果您要要了解更多,我有一篇关于该主题的简短文章:深度精度可视化。

评论


$ \ begingroup $
我想了解深度缓冲区的用途。我只尝试过线框渲染器,因此在将3D点绘制到2D屏幕时,我没有考虑深度(我可以按任何顺序绘制点和线,看起来很正确)。深度缓冲区的目的是在将每个点投影到2D时保持每个点Z距离的记录,以便可以正确的顺序绘制实体多边形吗?这就是为什么我在简单的线框可视化器中不需要近/远平面吗?
$ \ endgroup $
–威廉·格雷(Vilhelm Gray)
17年5月17日在18:01

$ \ begingroup $
@VilhelmGray正确,深度缓冲区记录每个像素处最近的表面的深度,因此在对三角形进行栅格化时,您可以判断该三角形是否应被先前渲染的像素遮挡。但是,如果您不关心深度排序(因为您正在绘制线框,则已经对三角形进行了预排序,或其他原因),则不需要深度缓冲区。
$ \ endgroup $
–内森·里德(Nathan Reed)
17年5月17日在18:31

#2 楼


在这种情况下,相似三角形ABC和ADE的几何形状用于通过DE的解确定D的高度。显而易见的是,如果近平面位于0(AE = 0),则将被0除-因此,为什么近平面无法位于位置0。


这就是为什么NearZ平面不能为零的原因。透视数学的目的不是将E投射到近平面上。如果查看实际的透视矩阵,则会发现nearZ仅适用于计算的剪辑空间Z坐标,不适用于X和Y。失去一个或多个维度。您正在从3D空间投影到2D空间。因此,投影将删除Z分量,从而将场景投影到空间的2D区域中。正射投影只是丢弃Z;透视投影会做一些更复杂的事情,根据Z重新调整X和Y的比例。

当然,我们并没有这样做。 Z仍然存在。否则,深度缓冲区将无法工作。但是基本的透视投影数学并没有定义Z的计算方式。

因此,我们可以根据需要计算Z。传统的深度方程式(对于OpenGL的标准NDC空间)是near / farZ的来源:

$$ Z_ {ndc} = \ frac {\ frac {Z_ {camera}(F + N)} {N-F} + \ frac {2NF} {N-F}} {-Z_ {camera}} $$

NF分别接近/ farZ。如果N为零,则等式退化:

$$ Z_ {ndc} = \ frac {\ frac {Z_ {camera}(F)} {-F} + 0} {-Z_ {相机}} $$
$$ Z_ {ndc} = \ frac {-Z_ {相机}} {-Z_ {相机}} $$
$$ Z_ {ndc} = 1 $$

糟糕。

所以您的问题确实是我们为什么要使用需要近似/ farZ值的深度计算(同样,与透视投影没有任何关系) 。

该方程式以及类似的方程式具有一些非常好的属性。它与透视投影所需的剪辑空间W分量(除以$ -Z_ {camera} $)相匹配。但是它也具有成为非线性Z投影的效果。它使场景的前端比远处的精度更高。通常,这是最需要深度精度的地方。

还有其他方法可以计算剪贴空间Z。您可以使用线性方法,该方法不会禁止Z在0附近。也可以使用允许无限远的远Z(但仍依赖于近Z)的方法;不过,这需要一个浮点Z缓冲区。依此类推。

您还没有真正显示您的代码,所以我不能说它是否真的“有效”。裁剪空间W特别重要,因为它用于对顶点数据进行透视校正的插值。如果将其设置为1,则将无法获得正确的透视校正插值。