法向纹理就是将法向量以颜色值的方式存储在纹理图中,一般情况下,就算没有法向纹理,模型也是有法向量的,那为什么还需要法向纹理呢?因为模型中的法向量数据,是和顶点一一对应的,而一个三角面片又是一个平面,因此一个三角面片上的法向量就是顶点的法向量,如果你注意观察,你会发现对于一个三角形来说,三个顶点的法向量是一样的,这里要注意顶点复用的情况,一个顶点位置有可能会对应多个法向量,取决于这个顶点是哪个三角形的顶点。这样对于一个三角面片来说,由于这个面所有地方的法向量都一样,因此在做光照计算时,就会得光照在一个非常光滑的平面上的效果,但是我们有时想得到一些粗糙表面的效果,比如这个经典的砖墙:
既然一个三角形是一个很平的平面,其中的法向量都一样,那如何得到粗糙的效果?可以做很多很密集的小三角形,让这些小角形朝向不同的地方,这样做有个显而易见的问题就是顶点数量变非常多,于是有大佬发明了法向纹理这个玩意,它将法向量存储在一张纹理中,在fragment shader中对法向量进行采样,得到像素级的法量向,能很方便地实现像素级凹凸不平的效果。
下面这张图展示了法向纹理能帮助我们得到像素级的法向量:
下面就来解释如何通过法向纹理得到模型上不同位置的法向量,前面提到过法向纹理是将法向量以颜色值的方式存储在纹理图中,也就是将(x,y,x)
以(r,g,b)
的方式存储,那么直接将颜色值读出来当作法向量的(x,y,z)
使用就行了?没那么简单,比如上面那个立方体,我们渲染时可以只用一张法图纹理,就能让6个面都有一样的凹凸不平的效果,如果说读出来的颜色值直接当法向量用,那么对于每个面上的对应位置,在法向纹理上采样得到的值是一样的,这样就会导致每个面上的这个点,法向量一样,如下面左所示,这显然不是我们想要的,我们想要的是下图右的效果:
当然也可以做6个法向图,每个面用自己的那个,也能解决这个问题