视差贴图(parallax mapping)学习笔记

时间:2022-06-02 04:47:32

视差贴图是一种很神奇的技术,它的效果有点类似法线贴图,都是通过尽可能少的面片加上特殊的技术来模拟复杂几何体的视觉效果。通常视差贴图都会和法线贴图结合起来使用。

视差贴图的核心思想,就是通过贴图时uv坐标的偏移,来形成视觉上的几何体高低视差,给人以立体的感觉。这篇教程很详细,下面的图片也是来自于该教程(捂脸):

视差贴图(parallax mapping)学习笔记

如图所示,高度为0.0的平面是渲染时的实际面片,棕色的线则代表了原始几何体的实际高度。这里我们一共需要三张纹理:法线纹理,高度纹理以及颜色纹理。

A点是我们在面片上看到的点,B点则是该几何体(如果是几何体而非一个面片的话)应该被我们所观察到的点,很明显A点和B点对应的纹理坐标是不同的,为了模拟实际的几何体表面,我们需要估计A B之间纹理坐标的偏移,这里又是一个“hack”,这里我们粗暴的将偏移量通过如下公式计算:

Xoffset=viewDir.x/viewDir.zH(A)factor

Yoffset=viewDir.y/viewDir.zH(A)factor

其中的 viewDir 是归一化之后的视线向量, H(A) 代表 A 点的高度。该公式虽然不精确,但是总体上符合视觉的规律。可以看出,当视线与平面的夹角越大, viewDir.x/viewDir.z 的比值也就越大,这样计算出来的偏移量也就越大,足以糊弄我们的眼睛。但是这样模拟出来的偏移量太大,需要调校一下 factor 这个参数,一般设置为0.1,使视觉效果达到最好。

通过这个UV偏移量得到实际的纹理坐标,然后再取该处的法向量和颜色值,最后得到的效果如下图。

视差贴图(parallax mapping)学习笔记

但是上述估计实在过于粗糙,当视线接近水平时,纹理会有很多地方发生扭曲。为了更精确的得出偏移量,又有了下面的方法:

steep parallax mapping

视差贴图(parallax mapping)学习笔记

这次我们将深度纹理分层,每层的间隔相同,然后用一种类似于raymarch的算法,沿着视线方向往下探,每次高度下降一层,当视线与某一层的交点的高度值小于该处深度贴图中的高度时停止。图中所示, T2 处的实际高度比该层的高度0.4要高,继续往下,到了 T3 时反过来了,因此我们就选取 T3 作为偏移之后的纹理坐标。用这种方式精度提升了很多,而且分层越细,精度越高。但是问题也随之而来,图片中产生了很明显的条带:

视差贴图(parallax mapping)学习笔记
 

视差贴图(parallax mapping)学习笔记

这些条带产生的原因如上图,注意其中的灰线和绿线,它们是进行“raymarch”时两层的分界线,他们对应的偏移后的纹理坐标区域(灰虚线和绿虚线之间的区域)有很多是重复的,这也就意味着看到的纹理也会因为重复而产生条纹。

线性插值

为了解决这个问题,我们通过线性插值的方式来确定偏移后的纹理坐标,使精度进一步提升,而且更平滑:

视差贴图(parallax mapping)学习笔记

如上图,现在我们不再简单的取 T3 作为偏移纹理了,根据一个比值 R 来对纹理坐标进行线性插值,现在图中的 H() 代表该点处实际高度与该层高度的差值的绝对值。

r=H(T3)/(H(T3)+H(T2))

Xoffset=T3.x(1r)+T2.xr

Yoffset=T3.y(1r)+T2.yr

r=1 时,偏移坐标为 T2 ,当 r=0 时,偏移坐标为 T3 。这样处理之后得到的效果就比较令人满意了,几乎没有瑕疵。

视差贴图(parallax mapping)学习笔记

最后很感谢参考文章中的作者,讲的深入浅出,插图也很直观(我顺便也可耻的利用了一下)。