Chapter 6 – Texturing 贴图

6.8 Parallax Mapping视差映射

凸起映射或者说法线映射最大的问题是,我们所“模拟”的凸起部分永远不会随着视角的改变而改变,或者说,凸起部分并不会互相“遮盖”。在现实生活中,如果我们看向一面砖块砌成的墙壁,在某些角度下,我们将无法看见砖块之间的凹槽。但是使用法线映射贴图的墙壁永远不能体现这一类的遮盖效果。因为其只是改变了物体表面的法线向量。因此更好的方法是让“凸起映射”能够改变物体表面每一个像素点的实际位置。

视差映射(parallax mapping)的概念在2001年被Kaneko提出并由Welsh进一步推动。视差(Parallax)的原理指的是,随着观察者的移动,物体的位置也进行改变。当观察者移动时,物体表面的凸起应该表现出“高度”。视差映射的关键在于,通过检测高度来决定一个像素应该显示哪些元素。

对于视差映射,凸起部分被存储于高度贴图中。当我们观察物体表面的某一个像素时,基于其位置读取高度值,并且使用该高度值来改变贴图坐标,以显示物体表面不同的部分。如下图所示。

我们的目标是实现上图中左侧部分:我们实际看到的物体表面的点应该是视野向量与高度曲线的交点位于多边形平面的投影点,也就是pideal。右侧部分则表示视差映射的原理,其读取p点的高度值,并与视野向量构成三角形,之后求出平移向量以得到一个新的像素点padj

高度值可以存储在一张独立的贴图中,或者存储在其他的颜色通道中(如果我们将高度值与其他属性,例如颜色值,混合在同一个RGBα中时会影响贴图的压缩质量)。在使用高度值对贴图坐标进行平移之前,我们会先对高度值进行缩放与偏移。其中,缩放决定了高度值的高度是多少,方向为表面的上方还是表面的下方;而偏移则表示基准面的高度。如果,贴图坐标为p,高度值为h,标准化的视野向量基于多边形表面的高度值为vz,水平方向的xy为vxy,那么通过视差调整的贴图坐标padj为:

需要注意的是,不同于其他的着色等式,上述计算中,视野向量必须位于切线空间,也就是贴图坐标所在的空间。

如果凸起部分高度的改变较为平缓,那么上述方法能够很好的模拟出效果。但是,当我们以较低的角度去观察物体时,这一方法便不再适用。当视野向量接近物体表面的水平面时,即使高度值的改变较小,其也会大大改变贴图坐标。那么我们新得到的贴图坐标将与原始的贴图坐标没有联系。

为了缓解这一问题,Welsh提出了平移限制这一理念。其原理就是限制平移量,并保证其不会大于高度值。其表达式为:

显然上述等式的计算速度比之前非限制的等式更快(我们不再需要除以vz)。几何意义上,像素点对应的高度值限定了像素点可移动的范围半径。如下图所示。

如果视野向量与多边形表面几乎垂直,那么上述等式就不会对贴图坐标进行平移(向量v是单位向量,vz几乎是1,那么vxy几乎为0)。视觉上,如果视野向量物体表面的夹角较小,那么凸起的效果也会较为“微弱”。虽然这一技术有一些限制,但是其能够大大改善法线映射贴图效果,且这一算法在像素着色器中的开销也非常少。

6.8.1 Parallax Occlusion Mapping(视差遮蔽映射)

凸起映射(bump mapping)并不会基于像素点的高度来修正贴图坐标;其只是改变了像素点的着色法线向量。视差映射则提供了一种简单的方法,模拟了像素点高度,且假设相邻像素的高度与原像素的高度相同。但这一假设也很可能并不成立。凸起映射永远不能形成遮蔽的效果或者投射阴影。而我们希望表现出的效果是,像素点应该是视野向量与高度层的交点。

为了更好地解决这个问题,一些研究者使用视野向量方向上的射线来检测视野向量与高度层的焦点。这可以通过像素着色器实现,而像素点的高度数据仍旧存储在贴图中。

这一类算法被称为视差遮蔽映射(parallax occlusion mapping)或者浮雕映射(relief mapping)。其主要原理是,首先沿着投影向量测试一组高度层贴图的采样点。通常在入射余角处我们使用更多的射线,这样我们就不会错失最近的相交点。我们读取射线上每一个三维坐标位置,并将其转换至贴图空间,之后我们就能够知道这些坐标位置是在高度层的上方还是下方。一旦我们找到一个采样点位于高度层的下方,那么该采样点之前的哪一个点就位于高度层的上方,也就是说该采样点可以认为是高度层与视野向量的交点,如下图所示。

上图中,我们使用绿色的射线表示视野向量,其被投影至物体表面的平面上,且以一定的频率进行采样(紫色的点),基于这些采样点,我们读取了高度值。这一算法能够求出视野射线与黑色线段的交点,而这些黑色线段则模拟了高度层。

之后我们将使用交点的贴图坐标来对表面进行着色,也就是说,将这一贴图坐标代入法线贴图,颜色贴图和其他各个类型的贴图中。我们将在第十三章中详细地学习多层级的高度层。

这方面有非常多的内容值得我们学习。但是所有的方法都是基于一条射线,就是视野向量。我们可以使用简单的贴图来表示高度值,也可以使用一个更为复杂的数据结果或者其他遍历方法。其他一些技术还包含在着色器中舍弃像素点或者写入depth buffer,不过这一定程度上会影响着色器的效率。以下我们总结了这些技术,随着GPU的不断进化,将来也会有更多更好的方法以解决这个问题。

找到两个采样点之间,视野向量与高度层的实际交点是一个“求根”的问题。实践中,高度层一般会被当做深度(depth)进行处理,同时使用一个矩形的平面来定义物体表面的上限。在找到最后一个位于高度层上方的采样点和第一个位于高度层下方的采样点之后,Tatarchuk使用了单步切割的方法来模拟视野向量与这两个点组成的线段的交点。Policarpo使用二分搜寻的方法来模拟一个更近的交点。如果使用常规的采样点,那么着色器中的计算能够保持并行,但是使用上述两种方法,我们则需要读取贴图的其他部分,也就是说必须等待其他的着色器完成计算。

最重要的一点是高度层的采样点足够充足。McGuire使用了anisotropic mipmap来保证高度层的采样率足够高。我们也可以让高度层贴图的分辨率高于法线映射贴图。此外,还有一些渲染系统可能并不会直接保存一张法线映射贴图,而是通过高度层的cross filter来计算出相应的法线。

另一种方法是不以固定的间隔对高度层进行采样。Donnelly高度层预处理为一组立体像素。

留下评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据