计算机图形学-笔记(8.3)

93 阅读8分钟

Category:Higher Mathematics & Computer Graphics Application

正文

8 图形管道

8.1栅格化

8.1.6 对平面进行裁剪

无论我们选择哪个选项,我们都必须夹在平面上。回顾第 2.5.5 节,通过点 q 且法线为 n 的平面的隐式方程为

image.png

这是经常写的:

image.png

有趣的是,这个方程不仅描述了 3D 平面,而且还描​​述了 2D 中的线和 4D 中平面的体积模拟。所有这些实体通常在其适当的维度上称为平面。

如果我们在点 a 和 b 之间有一条线段,我们可以使用在第 12.4.3 节中描述的 BSP 树程序中切割 3D 三角形边缘的技术将其“裁剪”到一个平面上。在这里,通过检查 f(a) 和 f(b) 是否具有不同的符号来测试点 a 和 b 以确定它们是否位于平面 f(p)=0 的相对侧。通常 f(p) < 0 被定义为平面“内部”,而 f(p) > 0 被定义为平面“外部”。如果平面确实分割了线,那么我们可以通过用方程代替参数线来求解交点,

image.png

进入方程 (8.2) 的 f(p)=0 平面。这产生

image.png

求解 t 给出

image.png

然后我们可以找到交点并“缩短”这条线。

要剪裁一个三角形,我们可以再次按照第 12.4.3 节生成一个或两个三角形。

8.2 光栅化前后的操作

在光栅化图元之前,定义它的顶点必须位于屏幕坐标中,并且必须知道应该在图元中插值的颜色或其他属性。准备这些数据是管道顶点处理阶段的工作。在这个阶段,传入的顶点通过建模、查看和投影变换进行变换,将它们从原始坐标映射到屏幕空间(回想起来,位置是以像素为单位测量的)。同时,其他信息,如颜色、表面法线或纹理坐标,根据需要进行变换;我们将在下面的示例中讨论这些附加属性。

在光栅化之后,进行进一步处理以计算每个片段的颜色和深度。这个处理可以像通过插值颜色并使用光栅化器计算的深度一样简单;或者它可能涉及复杂的着色操作。最后,混合阶段将重叠每个像素的(可能有几个)基元生成的片段组合起来,以计算最终颜色。最常见的混合方法是选择深度最小(离眼睛最近)的片段颜色。

不同阶段的目的最好通过例子来说明。

8.2.1 简单的二维绘图

最简单的管道在顶点或片段阶段什么都不做,而在混合阶段,每个片段的颜色只会覆盖前一个片段的值。应用程序直接以像素坐标提供图元,光栅化器完成所有工作。这种基本安排是许多用于绘制用户界面、绘图、图形和其他 2D 内容的简单、旧 API 的本质。可以通过为每个图元的所有顶点指定相同的颜色来绘制纯色形状,并且我们的模型管道还支持使用插值平滑改变颜色。

8.2.2 最小的 3D 管线

要在 3D 中绘制对象,2D 绘制管道所需的唯一更改是单个矩阵变换:顶点处理阶段将传入的顶点位置乘以建模、相机、投影和视口矩阵的乘积,从而产生屏幕-然后以与直接在 2D 中指定的相同方式绘制空间三角形。

最小 3D 管道的一个问题是,为了获得正确的遮挡关系——在更远的对象之前获得更近的对象——必须以从后到前的顺序绘制图元。这被称为去除隐藏表面的画家算法,类似于先绘制一幅画的背景,然后在其上绘制前景。画家算法是去除隐藏表面的一种完全有效的方法,但它有几个缺点。

它无法处理相互交叉的三角形,因为没有正确的绘制顺序。同样,几个三角形,即使不相交,仍然可以排列成一个遮挡循环,如图 8.9 所示,这是不存在从后到前顺序的另一种情况。最重要的是,按深度对图元进行排序很慢,尤其是对于大型场景,并且会扰乱使对象顺序渲染如此之快的有效数据流。图 8.10 显示了当对象没有按深度排序时这个过程的结果。

image.png

image.png

8.2.3 为隐藏表面使用 z-Buffer

在实践中,画家算法很少使用;取而代之的是一种简单有效的隐藏表面去除算法,称为 z-buffer 算法。该方法非常简单:在每个像素处,我们跟踪到目前已绘制的最近表面的距离,并丢弃比该距离更远的片段。除了红色、绿色和蓝色颜色值(称为深度或 z 值)之外,通过为每个像素分配一个额外值来存储最近距离。深度缓冲区或 z 缓冲区是深度值网格的名称。

z-buffer 算法是在片段混合阶段实现的,通过将每个片段的深度与存储在 z-buffer 中的当前值进行比较。

如果片段的深度更接近,它的颜色和深度值都会覆盖当前在颜色和深度缓冲区中的值。如果片段的深度较远,则将其丢弃。为了确保第一个片段将通过深度测试,z 缓冲区被初始化为最大深度(远平面的深度)。无论绘制表面的顺序如何,相同的片段都将赢得深度测试,并且图像将是相同的。

当然,深度测试中可能存在关系,在这种情况下,顺序可能很重要。

z-buffer 算法要求每个片段携带一个深度。这可以简单地通过将 z 坐标作为顶点属性进行插值来完成,就像插值颜色或其他属性一样。

z 缓冲区是在对象顺序渲染中处理隐藏表面的一种简单实用的方法,它是迄今为止占主导地位的方法。它比将表面切割成可以按深度排序的块的几何方法要简单得多,因为它避免了解决任何不需要解决的问题。深度顺序只需要在像素的位置确定,这就是 z-buffer 所做的一切。它得到硬件图形管线的普遍支持,也是软件管线最常用的方法。图 8.11 显示了一个示例结果。 image.png

image.png

精度问题

实际上,存储在缓冲区中的 z 值是非负整数。这比真正的浮点数更可取,因为 z 缓冲区所需的快速内存有点昂贵,值得保持在最低限度。

使用整数会导致一些精度问题。如果我们使用具有 B 值 {0, 1,...,B -1} 的整数范围,我们可以将 0 映射到近裁剪平面 z = n 并将 B-1 映射到远裁剪平面 z = f。请注意,对于本次讨论,我们假设 z、n 和 f 为正数。这将导致与否定情况相同的结果,但论证的细节更容易理解。我们将每个 z 值发送到深度为 Δz = (f - n)/B 的“桶”。如果内存不是溢价,我们将不会使用整数 z 缓冲区,因此使 B 尽可能小很有用。

如果我们分配 b 位来存储 z 值,则 B = 2b。我们需要足够的位来确保另一个三角形前面的任何三角形都将其深度映射到不同的深度箱。

例如,如果您正在渲染一个三角形间距至少为一米的场景,那么 Δz < 1 应该会产生没有伪影的图像。有两种方法可以使 Δz 变小:将 n 和 f 移近或增大 b。如果 b 是固定的,因为它可能在 API 或特定硬件平台上,调整 n 和 f 是唯一的选择。

在创建透视图像时,必须非常小心地处理 z 缓冲区的精度。上面的 Δz 值是在透视除法之后使用的。

回想第 7.3 节,透视划分的结果是

image.png

实际的 bin 深度与 zw(世界深度)有关,而不是与 z(后透视分割深度)有关。我们可以通过区分两边来近似 bin 大小:

image.png

垃圾箱大小的深度不同。世界空间中的 bin 大小为

image.png

请注意,数量 Δz 如前所述。最大的 bin 将是 z' = f,其中

image.png

请注意,如果我们不想丢失眼前的物体,选择 n = 0 是很自然的选择,这将导致无限大的垃圾箱——这是一个非常糟糕的情况。为了使 image.png尽可能小,我们希望最小化 f 并最大化 n。因此,仔细选择 n 和 f 总是很重要的。