6.6 透明贴图 Alpha Mapping
alpha值可以用于许多使用alpha混合或alpha测试的效果,例如高效渲染树叶、爆炸和远处的物体等等。本节将讨论alphas中纹理的使用,并指出各种限制和解决方案。
一个与纹理相关的效果是贴花。例如,你想在茶壶上放一张花的照片。你想要的不是整个画面,而是花朵所在的部分。通过为texel分配一个alpha值(0),可以使它透明,这样就不会产生任何效果。因此,通过正确设置贴花纹理的alpha值,您可以用贴花替换或混合底层表面。通常,Clamp对应函数与透明边框一起使用,将贴花的单个副本(相对于重复纹理)应用于表面。图6.26显示了如何实现标记的示例。有关贴花的更多信息,请参见第20.2节。
alpha的一个类似应用是在制作裁剪。假设你制作了一个贴花的灌木图像,并将它应用到场景中的一个矩形上。原则与贴花是相同的,除了不是与底面齐平,灌木将被绘制在它后面的任何几何图形的顶部。通过这种方式,使用单个矩形,您可以呈现具有复杂轮廓的对象。
在灌木的例子中,如果观察者绕着它进行旋转,那么图像会显示不正确,因为灌木没有厚度。一种方法是复制这个矩形并沿树干旋转90度。这两个矩形形成了一个便宜的三维灌木,有时被称为“交叉树”[1204],从地面上看,这种错觉相当有效。参见图6.27。Pelzer[1367]讨论了一个类似的配置,使用三个裁切面来表示草。在第13.6节中,我们将讨论一种称为billboarding的方法,它用于将这种呈现减少到单个矩形。如果观众移动到地面以上,这种错觉就会消失,因为从上面可以看到灌木是两个裁剪的。参见图6.28。为了解决这个问题,可以通过不同的方式添加更多的剪纸——切片、树枝、图层——来提供更令人信服的模型。第13.6.5节讨论了生成此类模型的一种方法;第857页的图19.31显示了另一个。有关最终结果的示例,请参见第2页和第1049页上的图像。
在灌木结合alpha贴图和纹理动画可以产生令人信服的特效,比如闪烁的火把、植物生长、爆炸和大气效果。
在灌木使用alpha映射呈现对象有几个选项。Alpha blend (Section 5.5)允许部分透明值,这允许反锯齿对象边缘,以及部分透明对象。然而,alpha混合需要在不透明三角形之后渲染混合三角形,并按前后顺序渲染。一个简单的交叉树是两个裁剪纹理的例子,其中没有正确的渲染顺序,因为每个四边形都在另一个的前面。即使理论上有可能排序并得到正确的顺序,但这样做通常也是低效的。例如,一块土地上可能有成千上万的草叶,这些草叶用裁切面表示。每个网格对象可以由许多单独的叶片组成。显式地对每个刀片进行排序是非常不切实际的。
在灌木在渲染时,这个问题可以通过几种不同的方式得到改善。一种是使用alpha测试,这是一个有条件地丢弃alpha值低于像素着色器中给定阈值的片段的过程。其中结果是这样的:
其中.a是来自纹理查找的alpha值,参数alphaThreshold是用户提供的阈值,它决定将丢弃哪些片段。这个二进制可见性测试允许三角形以任何顺序渲染,因为透明片段被丢弃。我们通常希望对alpha值为0.0的任何片段执行此操作。丢弃完全透明的片段还有一个额外的好处,即节省了进一步的着色器处理和合并的成本,以及避免在z缓冲区中错误地将像素标记为可见的[394]。对于裁剪,我们通常将阈值设置为高于0.0,比如0.5或更高,然后进一步忽略alpha值,而不是将其用于混合。这样做可以避免无序的渲染瑕疵。但是,质量很低,因为只有两种透明级别(完全不透明和完全透明)可用。另一种解决方案是为每个模型执行两个遍历——一个用于实体裁剪,它被写入z缓冲区;另一个用于非实体裁剪的半透明的采样。
在灌木alpha测试还有另外两个问题,即放大太多[1374]和缩小太多[234,557]。当alpha测试与mipmapping一起使用时,如果不采用不同的处理方法,效果可能无法令人信服。图6.29的顶部显示了一个示例,其中树的叶子变得比预期的更加透明。这可以用一个例子来解释。假设我们有一个一维纹理,它有四个alpha值,即(0.0,1.0,1.0,0.0)。通过平均,下一个mipmap级别变为(0.5,0.5),然后最高级别为(0.5)。现在,假设我们使用αt = 0.75。当访问mipmap level 0时,可以看到4个文本中有1.5个文本将通过丢弃测试。但是,当访问下两个级别时,将从0.5 < 0.75开始丢弃所有内容。另一个例子见图6.30。
Casta˜no [234] 提个了一个简单的解决方案使得mipmap可以正常工作。对于级别k的mipmap,覆盖率ck被定义为:
nk是mipmap在等级k上的texel数量,α(k, i)是第k级mipmap在pixel i上面产生的alpha值,方程6.9和αt是用户提供的α阈值。在这里,我们假设的结果α(k, i) > αt为真的时候是1,否则为0。注意,k = 0表示mipmap的最低级别,即,原始图像。对于每一个Mipmap水平,然后我们找到一个新的mipmap阈值 αk,而不是使用αt,这样ck等于c0(或尽可能接近)。这可以通过二分查找来实现。最后,所有k级的mipmap的texel产生的α值被缩放到αt/αk的水平。这种方法在图6.29的底部使用,并且在NVIDIA的纹理工具中支持这种方法。Golus[557]给出了一个不修改mipmap的变体,但是随着mipmap级别的增加,alpha值在着色器中被放大。
在灌木Wyman和McGuire[1933]提出了一个不同的解决方案,其中公式6.9中的代码行理论上被替换为:
在灌木随机函数返回[0,1]中的一个均匀值,这意味着平均而言,这将得到正确的结果。例如,如果纹理查找的alpha值为0.3,则有30%的几率丢弃该片段。这是一种随机透明的形式,每个像素只有一个样本[423]。在实际应用中,为了避免时空高频噪声,将随机函数替换为哈希函数:
三维哈希是通过对上述函数的嵌套调用形成的,即, float hash3D(x,y,z){return hash2D(hash2D(x,y),z);返回一个[0,1]中的数字。散列的输入是对象空间坐标除以对象空间坐标的最大屏幕空间导数(x和y),然后clamping。为了获得z方向运动的稳定性,需要进一步的注意,该方法最好与累积抗混叠技术相结合。这种技术随着距离的增加而逐渐消失,因此在近距离观察时我们根本不会得到任何随机效应。这种方法的优点是,平均每个片段都是正确的,Casta˜no的方法[234]为每个mipmap等级创建单个αk。然而,这个值可能在每个mipmap级别上有所不同,这可能会降低质量并需要艺术家的干预。
Alpha测试显示放大下的纹波瑕疵,这可以通过将Alpha映射作为距离场进行预计算来避免[580] (参见677页的讨论)。
透明度转换到覆盖率,以及类似的特性 transparency adaptive antialiasing。取片段的透明度,并且将其转换为一个像素内包含多少样本[1250]。这个想法就像第5.5节中描述的纱门透明度,但是是亚像素级的。假设每个像素有四个样例位置,一个片段覆盖一个像素,但是由于裁剪纹理,它是25%透明的(75%不透明)。透明度转覆盖模式使片段变得完全不透明,但是它只覆盖了四个样本中的三个。这种模式对于重叠草叶的纹理裁剪非常有用,例如[887,1876]。由于每个绘制的样本都是完全不透明的,所以最近的叶片将沿着边缘以一致的方式隐藏后面的对象。正确混合半透明边缘像素不需要排序,因为alpha混合是关闭的。
Alpha转覆盖率对于抗混叠的Alpha测试很好,但是当Alpha混合时可能会产生瑕疵。例如,具有相同alpha覆盖率的两个alpha混合片段将使用相同的亚像素模式,这意味着一个片段将完全覆盖另一个片段,而不是与之混合。Golus[557]讨论了使用fwidth()着色器指令使内容的边缘更清晰。参见图6.31。
对于任何alpha映射的使用,了解双线性插值如何影响颜色值是很重要的。想象两个texel邻近:rgbα=(255,0,0,255)是一个实心的红色,和它的邻居,rgbα=(0,0,0,2),是黑色的,几乎完全透明。二个texel之间的位置的rgba值应该取什么?简单的插值给出(127,0,0,128),结果rgb值是一个暗红色。然而,这个结果实际上并没有变暗,它是一个大红色,已经预先乘以alpha值了。如果你插值alpha值,为了得到正确的插值,你需要确保被插值的颜色在插值之前已经预先乘以alpha了。举个例子,想象一下几乎透明的临近像素是用rgbα=(0 255 0,2),给出一个极小的绿色色调进行取代。这个临近texel的预乘版本是(0,2,0,2),它给出了(127,1,0,128)的正确预乘结果。这个结果更有意义,因为预乘得到的颜色大多是红色,带有一点难以察觉的绿色。
忽略双线性插值的结果会得到一个预乘结果,这可能会导致在贴花和裁剪对象周围出现黑色边缘。“变暗的”红色的结果被处理成管道其余部分的未乘色,边缘变成黑色。即使使用alpha测试,这种效果也是可见的。最好的策略是在双线性插值完成之前进行预乘[490,648,1166,1813]。WebGL API支持这一点,因为组合对于web页面非常重要。然而,双线性插值通常是由GPU执行的,着色器在执行这个操作之前不能对texel值进行操作。图像不会以PNG等文件格式进行预乘,因为这样做会失去颜色精度。在使用alpha映射时,这两个因素结合在一起会导致默认情况下的黑边。一种常见的解决方法是对裁剪图像进行预处理,将透明的“黑色”纹理涂成附近不透明纹理的颜色[490,685]。所有透明区域通常都需要以这种方式重新绘制,手工或自动绘制,这样mipmap级别也可以避免边缘问题[295]。同样值得注意的是,当使用alpha值形成mipmaps时,应该使用预乘值[1933]。
6.7 凹凸贴图 Bump Mapping
本节描述了一大类我们统称为bump mapping的小规模细节表示技术。所有这些方法通常都是通过修改每个像素的着色例程来实现的。它们比单独的纹理映射提供了更三维的外观,但没有添加任何额外的几何形状。
对象上的细节可以分为三个尺度:覆盖多个像素的宏观特征、跨越几个像素的中观特征和实质上小于一个像素的微观特征。这些类别在某种程度上是不固定的,因为在动画或交互会话期间,观察者可以在许多距离上观察同一个对象。
微几何由顶点和三角形或其他几何原语表示。当创建一个三维人物时,四肢和头部通常是在宏观尺度上建模的。微几何封装在阴影模型中,通常在像素着色器中实现,并使用纹理映射作为参数。使用的阴影模型模拟了表面微观几何结构的相互作用,例如,有光泽的物体在微观上是光滑的,而漫反射的表面在微观上是粗糙的。角色的皮肤和衣服似乎有不同的材质,因为它们使用不同的着色器,或者至少在这些着色器中使用不同的参数。
中几何描述了这两个尺度之间的一切。它包含的细节过于复杂,无法有效地使用单个三角形呈现,但它足够大,可以让观察者在几个像素上区分表面曲率的单个变化。人物脸上的皱纹、肌肉组织的细节、衣服上的褶皱和接缝都是中尺度的。一组统称为凹凸贴图技术的方法通常用于中尺度建模。这些调整在像素级的阴影参数,这样观众就能感觉到基本几何形状的小扰动,而基本几何实际上是平坦的。不同类型凹凸贴图的主要区别在于它们如何表示细节特征。变量包括逼真度和细节特性的复杂性。例如,数字艺术家通常将细节雕刻到模型中,然后使用软件将这些几何元素转换成一个或多个纹理,比如凹凸纹理,或者渐暗纹理。
Blinn在1978年提出了在纹理中编码中尺度细节的想法[160]。他观察到,如果在着色过程中,我们用一个轻微扰动的正常表面代替真实的表面,那么表面似乎具有小规模的细节。他把描述扰动到表面法线的数据存储在数组中。
关键的思想是,我们不是使用纹理来改变光照方程中的颜色分量,而是使用纹理来修改表面法线。曲面的几何法线保持不变;我们只是修改了照明方程中使用的法线。这个操作没有物理上的等价;我们改变表面的法线,但表面本身在几何意义上保持光滑。就像每个顶点都有法线会让人产生三角形之间表面光滑的错觉一样,修改每个像素的法线会改变三角形表面本身的感知,而无需修改其几何形状。
对于凹凸贴图,法线必须相对于某些参照系改变方向。为此,在每个顶点上存储一个切坐标系,也称为切空间基。这个参照系被用来将光转换到一个表面位置的空间(反之亦然),以计算扰动法线的效果。对于一个应用法线贴图的多边形曲面,除了顶点法线外,我们还存储了切向量和副切线向量(bitangent vectors)。bitangent vector也被错误地称为binormal vector[1025]。
切线矢量和副切线向量表示法线贴图本身在物体空间中的坐标轴,因为目标是将光线转换为相对于贴图的光线。参见图6.32。
这三个向量,法向量n,切线向量t,和副切线 b,构成一个基矩阵:
这个矩阵,有时简写为TBN,将光的方向(对于给定的顶点)从世界空间转换为切线空间。这些向量不必彼此垂直,因为法线贴图本身可能会被扭曲以适应曲面。然而,非正交基会导致纹理倾斜,这意味着需要更多的存储空间,也会影响性能,即,则矩阵不能被简单的转置所倒转[494]。一种节省内存的方法是只存储顶点处的切线和副切线,然后求它们的叉乘来计算法线。然而,只有当矩阵的旋向性总是相同时,这种方法才有效[1226]。模型通常是对称的:飞机、人、文件柜和许多其他对象。因为纹理消耗大量内存,所以它们常常被镜像到对称模型上。因此,只存储对象纹理的一侧,但是纹理映射将其放在模型的两侧。在这种情况下,切空间的旋向性在两边是不同的,不能假设。在这种情况下,如果在每个顶点都存储了额外的信息来表示利手性,仍然可以避免存储法线。如果设置好了,这个位就用来抵消正切和位元的叉乘,从而得到正确的法线。如果切线帧是正交的,也可以将基存储为四元数(Section 4.3),这不仅更节省空间,而且每像素可以节省一些计算[494,1114,1154,1381,1639]。质量上的小损失是可能的,尽管在实践中很少见到。
切线空间的概念对于其它算法是很重要的。正如在下一章所讨论的,许多着色方程只依赖于表面的法线方向。然而,拉丝铝或天鹅绒等材料也需要知道相对于表面的观察者的相对方向和光线。切线坐标系对于定义材料在表面上的方向是有用的。冷耶尔[1025]和米特林[1226]的文章对这一领域进行了广泛的覆盖。sch¨uler[1584]提出了一种在像素着色器中动态计算切线空间基的方法,不需要为每个顶点存储预先计算好的切线帧。Mikkelsen[1209]改进了这一技术,推导出一种不需要任何参数化的方法,而是使用表面位置的导数和高度场的导数来计算扰动法线。然而,与使用标准的切线空间映射相比,这种技术带来的显示细节要少得多,而且可能会产生艺术工作流问题[1639]。
6.7.1 Blinn’s Methods
Blinn的原始凹凸映射方法在纹理中的每个texel上存储两个带符号的值bu和bv。这两个值对应的是沿着u和v图像轴变化法线的量。也就是说,这些纹理值,通常是双线性插值的,用来缩放两个垂直于法线的向量。这两个向量加到法线上改变方向。两个值bu和bv描述了曲面在该点的方向。参见图6.33。这种类型的凹凸贴图纹理称为偏移矢量凹凸贴图或偏移贴图。
另一种表示凸起的方法是使用高度场来修改表面法线的方向。每个单色纹理值表示一个高度,因此在纹理中,白色是一个高区域,黑色是一个低区域(反之亦然)。有关示例,请参见图6.34。这是第一次创建或扫描凹凸贴图时使用的一种常见格式,Blinn在1978年也引入了这种格式。高度场用于派生与第一种方法中使用的u和v符号值类似的值。这是通过取相邻列之间的差来得到u的斜率,取相邻行之间的差来得到v的斜率[1567]。一种变体是使用Sobel过滤器,它给直接相邻的texel更大的权重[535]。
6.7.2 法线贴图 Normal Mapping
凹凸贴图的一种常用方法是直接存储法线贴图。算法和结果与Blinn方法在数学上是一致的;只有存储格式和像素着色器计算发生了变化。
法线贴图编码(x, y, z)映射到[-1,1],例如,对于一个8位的纹理,x轴值0代表-1.0,255代表1.0。图6.35显示了一个示例。颜色[128,128,255]为淡蓝色,表示所示颜色映射的平面,即,法线为[0,0,1]。
法线图表示最初是作为世界空间法线图引入的[274,891],在实践中很少使用。对于这种类型的映射,扰动是很简单的:在每个像素处,从映射中检索法线,并直接使用它,连同光的方向,来计算该位置在表面上的阴影。法线映射也可以在对象空间中定义,这样模型就可以旋转,法线仍然有效。然而,world和object-space表示都将纹理绑定到特定方向的特定几何形状,这限制了纹理的重用。
相反,扰动法线通常在切线空间中检索,即,相对于表面本身。这允许表面变形,以及最大限度地重用正常纹理。切线空间法线映射也可以很好地压缩,因为z分量的符号(与未扰动表面法线对齐的符号)通常可以假定为正的。
法线映射可以很好地增强现实感,参见图6.36。
与过滤颜色纹理相比,过滤法线贴图是一个比较困难的问题。一般来说,法线和阴影颜色之间的关系不是线性的,所以标准的滤波方法可能会导致令人讨厌的混叠。想象一下,楼梯是由闪闪发光的白色大理石砌成的。在某些角度上,楼梯的顶部或侧面会吸收光线,并反射出明亮的高光。然而,楼梯的平均法线是45度角;它将从与原来楼梯完全不同的方向捕捉亮点。当带有高光的凹凸贴图在没有正确过滤的情况下被渲染时,由于高光在样本降低的地方闪烁,会产生分散注意力的闪烁效果。
Lambertian曲面是一种特殊的情况,在这种情况下,法线贴图对着色的效果几乎是线性的。Lambertian着色几乎完全是一个点积,这是一个线性操作。对一组法线求平均值并执行点积,其结果相当于对单个点积求平均值:
注意,平均向量在使用之前没有标准化。由式6.14可以看出,标准滤波和mipmaps对于Lambertian曲面几乎产生了正确的结果。结果并不完全正确,因为Lambertian渲染方程不是点积;它是一个clamp点积max(l·n, 0),clamp操作使其非线性。这将使表面过度变暗,使光的方向发生偏光,但在实践中,这通常并不令人反感[891]。需要注意的是,通常用于法线映射的一些纹理压缩方法(例如从其他两个方法重构zcomponent)不支持非单位长度法线,因此使用非标准化法线映射可能会造成压缩困难。
在 non-Lambertian 曲面的情况下,将渲染方程的输入作为一个整体过滤,而不是单独过滤法线贴图,可能会产生更好的结果。实现这一点的技术将在第9.13节中讨论。
最后,从高度图h(x, y)中导出法线图可能是有用的。首先,在x和y方向上的导数的近似值是用中心差分来计算的
则在texel (x, y)处的非标准化法线为
必须注意纹理的边界。
水平线映射[1027]可以通过让凸起能够将阴影投射到它们自己的表面来进一步增强法线贴图。这是通过预先计算额外的纹理来完成的,每个纹理都与表面平面的一个方向相关联,并为每个texel存储地平线在那个方向的角度。有关更多信息,请参见第11.4节。
6.8 视差映射 Parallax Mapping
凹凸和法线贴图的一个问题是凹凸不会随着视角移动位置,也不会相互遮挡。例如,如果你沿着真实的砖墙看,从某个角度你不会看到砖与砖之间的灰泥。墙壁的凹凸贴图永远不会显示这种类型的遮挡,因为它只是改变了法线情况。更好的方法是让凹凸实际影响表面上的哪个位置在每个像素处呈现。
视差映射的概念由Kaneko[851]于2001年提出,Welsh[1866]对其进行了改进和推广。视差是指当观察者移动时,物体的位置相对移动。当观众移动时,这些凸起应该看起来有高度。视差映射的关键思想是通过检查发现的可见点的高度,对像素中应该看到的内容进行有根据的猜测。
对于视差贴图,凹凸点存储在一个高度场纹理中。当查看给定像素处的表面时,会在该位置检索高度场值,并用于移动纹理坐标以检索表面的不同部分。移动的量是基于获取的高度和眼睛到表面的角度。参见图6.37。高度场值要么存储在单独的纹理中,要么打包在其他纹理的未使用颜色或alpha通道中(打包不相关的纹理时必须小心,因为这会对压缩质量产生负面影响)。在使用高度场值移动坐标之前,会对其进行缩放和偏移。这个比例尺决定了高度场在地表之上或之下延伸的高度,而偏差给出了“海平面”的高度,在这个高度上不会发生位移。给定纹理坐标位置p,调整高度h,高度值vz和水平分量vxy的归一化视图向量v,新的平行调整纹理坐标padj
注意,与大多数着色方程不同,这里执行计算的空间很重要——视图向量需要在切线空间中。
虽然这只是一个简单的近似,但如果碰撞高度变化相对较慢,这种偏移在实际应用中会相当有效[1171]。附近相邻的texel具有相同的高度,因此使用原始位置的高度作为新位置高度的估计值是合理的。然而,这种方法在浅视角下就行不通了。当视图向量接近地表地平线时,一个小的高度变化会导致较大的纹理坐标偏移。由于检索到的新位置与原始表面位置的高度相关性很小,甚至没有相关性,因此近似是失败的。
为了改善这个问题,Welsh[1866]引入了偏移限制的概念。这样做的目的是限制移动量,使其永远不会超过检索到的高度。方程是
注意,这个方程的计算速度比原来的方程快。几何上的解释是,高度定义了一个半径,超过这个半径位置就不能移动。如图6.38所示。
在陡(面)角处,由于vz接近1,这个方程几乎与原来的方程相同。在较浅的角度,偏移量的影响会受到限制。在视觉上,这使得凹凸度在浅角度上减小,但这比随机采样纹理要好得多。随着视图的变化,纹理也会出现问题,或者对于立体渲染,在这种情况下,观察者同时感知两个必须提供一致深度提示的视点[1171]。即使有这些缺点,视差映射与抵消限制成本只是几个额外的像素着色器程序指令,并提供了一个相当大的图像质量改善比基本的法线映射。Shishkovtsov[1631]通过沿着凹凸贴图法线方向移动估计位置,改进了视差遮挡的阴影。
6.8.1 视差遮挡映射 Parallax Occlusion Mapping
凹凸贴图不修改基于高度场的纹理坐标;它只改变一个位置的Normal着色。视差映射提供了一个简单的高度场效应近似,假设一个像素的高度与其相邻像素的高度大致相同。这种假设可能很快就会被打破。凹凸也不会相互遮挡,也不会产生阴影。我们想要的是在像素处可见的东西,即视图向量与高度场的第一个交点。
为了更好地解决这个问题,一些研究人员建议使用光线沿着视图向量行进,直到找到一个(近似的)交点。这项工作可以在像素着色器中完成,其中高度数据可以作为纹理访问。我们将对这些方法的研究归纳为视差映射技术的一个子集,这些技术以这样或那样的方式利用光线行进[192, 1171, 1361, 1424, 1742, 1743]。
这些类型的算法被称为视差遮挡映射(POM)或浮雕映射方法,以及其他名称。其关键思想是首先沿着投影向量测试一定数量的高度场纹理样本。对于掠入射角度的视图射线,通常会生成更多的样本,这样就不会错过最近的交点[1742,1743]。沿着光线的每个三维位置都被检索出来,转换成纹理空间,并进行处理,以确定它是在heightfield之上还是之下。一旦找到了高度场下面的一个样本,它下面的数量,以及之前的样本上面的数量,将被用来找到一个交集位置。参见图6.39。然后,使用所附的法线贴图、彩色贴图和任何其他纹理,使用该位置对表面进行着色。多层高场可用于产生悬挑、独立的重叠表面和双面浮雕假体;参见13.7节。高度场跟踪方法也可以用来让凹凸不平的表面投射阴影到它自己,无论是硬的[1171,1424]还是软的[1742,1743]。比较请参见图6.40。
关于这个话题有大量的文献。虽然所有这些方法都是沿着一条射线前进的,但是有几个不同之处。可以使用简单的纹理来检索高度,但是也可以使用更高级的数据结构和更高级的rootfinding方法。一些技术可能涉及着色器丢弃像素或写入深度缓冲区,这会损害性能。下面我们总结了大量的方法,但是请记住,随着gpu的发展,最好的方法也在发展。这种“最佳”方法取决于ray行进过程中的内容和步骤数。
确定两个规则样本之间的实际交点问题是一个寻根问题。在实践中,高度场更多地被视为深度场,矩形的平面定义了曲面的上限。这样,平面上的初始点就在高度场的上方。Tatarchuk[1742, 1743]在找到了上面的最后一个点和下面的第一个点后,利用割线法的单一步骤找到了一个近似解。Policarpo 等人[1424]使用二叉搜索发现的两个点之间的一个更接近的交集。Risser等人[1497]通过使用secant 方法迭代来加速收敛。其折衷之处是可以并行地进行常规采样,而迭代方法需要更少的总体纹理访问,但必须等待结果并执行更慢的依赖纹理获取。蛮力方法似乎在整体上表现良好[1911]。
足够频繁地对高度场进行采样是至关重要的。McGuire和McGuire[1171]提出对mipmap查找进行偏导,并使用各向异性mipmap来确保对高频高度场(如表示尖峰或毛发的高场)的正确采样。人们还可以存储比法线贴图分辨率更高的高度场纹理。最后,有些渲染系统甚至不存储法线贴图,而是使用交叉过滤器[40]动态地从高度场导出法线。696页的方程16.1给出了该方法。
提高性能和采样精度的另一种方法是不首先定期采样heightfield,而是尝试跳过中间的空格。Donnelly[367]将高度场预处理成一组体素,存储在每个体素与高度场表面的距离中。通过这种方式,可以快速跳过中间的空间,代价是为每个heightfield增加存储空间。Wang等[1844]使用五维位移映射方案来保持从所有方向和位置到表面的距离。这允许复杂的曲面、自阴影和其他效果,但代价是相当大的内存。Mehra和Kumar[1195]出于类似的目的使用方向距离地图。Dummer[393]引入了锥阶映射的思想,并且Policarpo和Oliveira[1426]对锥阶映射的思想进行了改进。这里的概念是为每个高度场位置存储一个圆锥体半径。这个半径定义了光线上的一个区间,其中与高度场交点最多为一个。这个属性允许沿着光线快速跳跃而不丢失任何可能的交叉点,尽管代价是需要依赖的纹理读取。另一个缺点是创建圆锥步骤映射所需的预计算,这使得该方法不能用于动态更改高度字段。Schroders和Gulik[1581]提出了四叉树地形映射,这是一种在遍历过程中跳过卷的分层方法。Tevs等人[1760]使用“最大mipmap”允许跳过,同时最小化预计算成本。Drobot[377]还使用存储在mipmaps中的四叉树结构来加速遍历,并提出了一种混合不同高度场的方法,其中一种地形类型转换为另一种地形类型。
上述所有方法的一个问题是,沿着物体轮廓边缘的错觉会被打破,这将显示出原始表面的光滑轮廓。参见图6.41。关键的思想是,呈现的三角形定义了像素着色器程序应该评估哪些像素,而不是表面的实际位置。此外,对于曲面,轮廓的问题变得更加复杂。一种方法是由Oliveira和Policarpo[1325,1850]描述和开发的,它使用二次剪影近似技术。Jeschke等[824]和Dachsbacher等[323]都给出了正确处理轮廓和曲面的更通用和健壮的方法(并回顾了以前的工作)。赫什(Hirche)[750]首先探索的是将网格中的每个三角形向外挤压,形成棱镜。渲染这个棱镜可以对所有可能出现高度场的像素进行评估。这种方法称为shell映射,因为扩展网格在原始模型上形成一个单独的shell。通过保持棱镜与光线相交时的非线性特性,可以实现对高度场的真实渲染,尽管计算起来很昂贵。图6.42显示了这种技术令人印象深刻的用法。
6.9 纹理灯光 Textured Lights
纹理也可以用来增加光源的视觉丰富性,并允许复杂的强度分布或聚光灯功能。对于所有的光照都限制在一个锥体或锥体上的光,投射纹理可以用来调节光的强度[1192,1597,1904]。这允许使用形状的聚光灯、有图案的灯,甚至是“幻灯机”效果(图6.43)。这些灯通常被称为gobo或cookie灯,以专业剧院和电影照明中使用的剪纸的术语命名。有关投影映射以类似的方式投射阴影的讨论,请参见第7.2节。