1. 为什么使用法线映射?
在开始正式讨论法线映射之前,先来看下以下两张图片:
这两张依然是之前一篇文章中用到的仙剑五前传中两张截图,两图中显示的为同一地点,不同的观察角度。在左边的图中,根据纹理图,它给人一种很粗糙的岩石壁的感觉,但右边图中却出现了强烈的高光反射。这显然是有点相互矛盾的,因为强烈的全反射只有在表面比较光滑的表面上才会出现,而从左图中来看,它应该是凹凸不平的。造成这种现象的原因很简单:纹理的使用给我们带来了像素级别上的物体表面的细节,而模型本身是由有限个顶点组成的,这样在像素着色器中,经过插值计算得到的各像素的法线是平滑过渡的,而不再是各像素本身应该有的法线值。这样平滑过渡的法线在经过光照计算后,就很容易造成这种比较明显的高光反射现象。
要修正这种现象,根本问题在于修改像素的法线值,使其与真实法线趋于一致,这样在光照计算后将会得到与实际逼近的结果。要实现这种效果,有两种方法:一种是增加模型的细节,即顶点个数,这样就可以为模型表面指定更多的法线,而不再是在像素着色阶段依赖简单的插值计算得到,以得到更加真实的效果。这种方法是可行的,但有一个缺陷,更多的顶点意味着更大的计算量,因为在顶点着色器中,每个顶点都要经过各自的各种矩阵变换。因此这种方法能够提供的细节程度是有限的,一般不足以满足我们的要求。 另一种效率非常高而且效果很好的方法,即这篇文章的主题:Normal Mapping。
2. 法线贴图 及其 数据格式
在Normal Mapping技术中,需要使到到一张纹理。与普通纹理不同的是,这张纹理中的每个像素(texel)存放的并不是颜色值,而是法线,因此也称之为法线贴图(Normal Map)。我们知道,纹理的使用给基于顶点的几何模型带来了像素级别上的细节,同样,法线贴图的使用,使用我们能够得到模型表面在像素级别上的法线值,这样的法线值是直接通知读取纹理获得的,而不再是经过插值得到,因此可以根据现实需求由美工们灵活设定,以获得想要的逼真效果。
在数据存放格式上,法线贴图与普通贴图并无差别,依然是RGB格式或者RGBA格式。只是这里的R、G、B、A不再是颜色的不同分量,而是三维法线向量的各分量。R、G、B分别代表法向量的X、Y、Z分量,如果是RGBA格式,则一般可以用A分量来存放高度信息。这个高度信息也是非常有用的,在很多地方需要与法线值配对使用,比如Parallax Mapping(后面介绍)。这里我们主要来关注RGB分量。一般情况下各分量占8个位(无符号),因此取值区间位于[0, 255]。但在实际情况下,经过归一化的法线向量,总长度为1,因此各分量都位于[-1,