Category:Higher Mathematics & Computer Graphics Application
正文
8 图形管道
8.2 光栅化前后的操作
8.2.4 逐顶点着色
到目前为止,将三角形发送到管道的应用程序负责设置颜色;光栅化器只是插入颜色并将它们直接写入输出图像。对于某些应用程序,这已经足够了,但在许多情况下,我们希望使用在第 4 章中用于图像顺序渲染的相同照明方程来绘制带有阴影的 3D 对象。回想一下,这些方程需要光的方向,眼睛的方向,以及用于计算表面颜色的表面法线。
处理着色计算的一种方法是在顶点阶段执行它们。应用程序在顶点处提供法向量,并且分别提供灯光的位置和颜色(它们不会在整个表面上变化,因此不需要为每个顶点指定)。对于每个顶点,观察者的方向和每个灯光的方向是根据相机、灯光和顶点的位置来计算的。评估所需的着色方程以计算颜色,然后将其作为顶点颜色传递给光栅化器。 Pervertex 着色有时也称为 Gouraud 着色。
要做出的一个决定是进行着色计算的坐标系。世界空间或眼睛空间是不错的选择。选择在世界空间中观察时正交的坐标系很重要,因为着色方程取决于向量之间的角度,而在建模转换中经常使用的非均匀比例或经常使用的透视投影等操作无法保留这些角度在对规范视图体积的投影中。眼睛空间着色的优点是我们不需要跟踪相机位置,因为相机在眼睛空间,透视投影中始终位于原点,或者在正交投影中,视图方向始终为 +z。
每个顶点着色的缺点是它不能在着色中产生任何小于用于绘制表面的图元的细节,因为它只为每个顶点计算一次着色,而从不在顶点之间计算。例如,在一个使用两个大三角形绘制地板并由房间中间的光源照明的房间中,阴影将仅在房间的角落进行评估,并且插值可能也会很大中间一片漆黑。此外,使用镜面高光着色的曲面必须使用足够小的图元来绘制,以便高光可以被解析。
图 8.13 显示了我们使用逐顶点着色绘制的两个球体。
8.2.5 每片段着色
为了避免与逐顶点着色相关的插值伪影,我们可以在片段阶段通过在插值之后执行着色计算来避免插值颜色。在逐片段着色中,评估相同的着色方程,但使用插值向量对每个片段进行评估,而不是使用应用程序中的向量对每个顶点进行评估。
在逐片段着色中,着色所需的几何信息作为属性通过光栅器传递,因此顶点阶段必须与片段阶段协调以适当地准备数据。一种方法是对眼睛空间表面法线和眼睛空间顶点位置进行插值,然后可以像在逐顶点着色中一样使用它们。
每个片段的着色有时也称为 Phong 着色,这很容易混淆,因为 Phong 照明模型附加了相同的名称。
图 8.14 显示了我们使用每个片段着色绘制的两个球体。
8.2.6 纹理映射
纹理(将在第 11 章讨论)是用于为表面的阴影添加额外细节的图像,否则这些表面看起来会过于均匀和人工。
这个想法很简单:每次计算着色时,我们从纹理中读取一个用于着色计算的值(例如漫反射颜色),而不是使用附加到正在渲染的几何图形的属性值。此操作称为纹理查找:着色代码指定纹理坐标、纹理域中的一个点,纹理映射系统在纹理图像中查找该点处的值并将其返回。然后在着色计算中使用纹理值。
定义纹理坐标最常见的方法是简单地将纹理坐标设置为另一个顶点属性。然后每个基元都知道它在纹理中的位置。
8.2.7 着色频率
关于在何处放置着色计算的决定取决于颜色变化的速度——计算细节的比例。具有大规模特征的着色,例如曲面上的漫反射着色,可以很少进行评估,然后进行插值:它可以用低着色频率计算。 产生小尺度特征的着色,例如清晰的高光或详细的纹理,需要在高着色频率下进行评估。对于需要在图像中看起来清晰明快的细节,着色频率需要至少为每个像素一个着色样本。
因此,即使定义原语的顶点相距许多像素,也可以在顶点阶段安全地计算大规模效应。只要顶点在图像中靠近,就可以在顶点阶段计算需要高阴影频率的效果。或者,当原语比像素大时,可以在碎片阶段计算它们。
例如,计算机游戏中使用的硬件管道通常使用覆盖多个像素以确保高效率的原始功能,通常每片片段进行大多数阴影计算。另一方面,感性的伦德曼系统(Renderman System)每一个顶点进行所有阴影计算,在首次细分或划分后,将所有表面都呈现为小四边形,称为微poly,称为微型小子,大约是像素的大小。由于原始图很小,因此该系统中的每个vertex阴影可达到适合详细阴影的高阴影频率。
8.3 简单抗锯齿
就像光线追踪一样,如果我们全有或全无地确定每个像素是否在图元内,光栅化将产生锯齿状线条和三角形边缘。事实上,本章描述的简单三角形光栅化算法生成的片段集(有时称为标准光栅化或别名光栅化)与发送一条光线的光线追踪器映射到该三角形的像素集完全相同通过每个像素的中心。
与光线追踪一样,解决方案是允许像素部分被图元覆盖(Crow,1978)。在实践中,这种形式的模糊有助于提高视觉质量,尤其是在动画中。这显示为图 8.15 的第一行。
在光栅化应用程序中有许多不同的抗锯齿方法。就像使用光线追踪器一样,我们可以通过将每个像素值设置为属于该像素的正方形区域上图像的平均颜色来生成抗锯齿图像,这种方法称为框过滤。这意味着我们必须将所有可绘制实体视为具有明确定义的区域。例如,图 8.15 中的线可以被认为是一个 1 像素宽的矩形。
实现箱式过滤器抗锯齿的最简单方法是超级采样:以非常高分辨率创建图像,然后进行下采样。例如,如果我们的目标是宽度为 1.2 像素的线条的 256 × 256 像素图像,我们可以在 1024 × 1024 的屏幕上栅格化宽度为 4.8 像素的线条的矩形版本,然后平均 4 × 4 组像素获取“缩小”图像中每个 256 × 256 像素的颜色。这是实际框过滤图像的近似值,但当对象相对于像素之间的距离不是非常小时时效果很好。
然而,超级采样非常昂贵。因为导致锯齿的非常锐利的边缘通常是由图元的边缘引起的,而不是图元内阴影的突然变化,所以广泛使用的优化是以比着色更高的速率对可见性进行采样。如果为每个像素内的几个点存储有关覆盖和深度的信息,即使只计算一种颜色,也可以实现非常好的抗锯齿。在像 RenderMan 这样使用逐顶点着色的系统中,这是通过以高分辨率进行光栅化来实现的:这样做的成本很低,因为着色被简单地插值以产生许多片段或可见性样本的颜色。在具有逐片段着色的系统中,例如硬件管道,通过为每个片段存储单一颜色加上覆盖掩码和一组深度值来实现多样本抗锯齿。
有比盒子更好的过滤器,但除了最苛刻的应用之外,盒子过滤器就足够了。