【法线贴图原理】
如果法线处于世界坐标中的(world space),那称为world space normal。如果是处于物体本身局部坐标中的,那称为object space normal。
很容易想象,world space normal一旦从贴图里解压出来后,就可以直接用了,效率很高。但是有个缺点,这个world space normal 是固定了,如果物体没有保持原来的方向和位置,那原来生成的normal map就作废了。
因此又有人保存了object space normal。它从贴图里解压,还需要乘以model-view矩阵转换到世界坐标,或者转换到其他坐标取决于计算过程及需求。object space normal生成的贴图,物体可以被旋转和位移.基本让人满意。但仍有一个缺点。就是一张贴图只能对应特定的一个模型,模型不能有变形(deform)。
变形时,顶点关系改变了,即面的形状,方向改变了。如果面上存在一个固定的坐标系,那当物体变形、移动、旋转时,这个坐标系必定跟着面一起运动,那么在这个坐标系里的某个点或向量,不需要变动。当整个面发生变化时,我们只需要计算面上的坐标系到世界坐标系的转换矩阵,那么定义在这个面上的点或坐标(固定的),乘以这个矩阵即可得到在世界中的坐标。这个坐标系术语里称为tangent space。
按照新方法每个面都有一个局部坐标系,当低模变形时,即三角面变化时,它的tangent space也会跟着变化,保存在贴图里的法线乘以低模这个面的tangent space到外部坐标系的转换矩阵即可得到外部坐标。
CG中顶点已经自带tangent、normal信息,TxN即可得到B。T、B、N即可构造出切换空间。
现在我们可以分析为什么tangent space法线贴图是偏蓝色了.因为这个面渲染时计算机认为这个面的"弯曲"程度很小,即面上各个点插值得来的法线相互间偏差很小.基本跟整个面的垂直方向不会差太多.因此在tangent space里,这些法线都跟z轴偏差较小.而z轴是被保存在贴图里的b字节处(蓝色通道)里.所以贴图显示出来的颜色就偏蓝了.
假设在低模上的某个面我们计算出了TBN矩阵,并取出了面上某点的对应在法线贴图里法线值.现在需要计算光照.我们可以把光向量转换到tangent space里做计算.也可以把得到的法向量转换到world space与光向量进行计算.结果是一样的.实际考量,你会发现后一种方法不好.因为对于面上的每个点,都要计算一次normal到world space的转换.而前一种方法,对一个面上的所有点,只要计算一次光向量到tangent space的计算.然后再考虑到vertex shader与fragment shader的流程,你会发现刚好我们可以在vertex shader计算光线到tangent space的转换,在fragment sader取出法线值与前面得到的tangent space里的光线方向做计算即可.这里提醒一下,一般verteix shader中我们得到的光线方向是基于world space的,而法线贴图保存的是高模的object space内的方向然后再转换到tangent space,所以在vertex shader中,我们必须先把光线先转换到object space,再转换到tangent space.这样才能保证最终计算时,光线与法线是基于同一个坐标系的.这也是你在很多normal map的shader里,看到类似ToOjectSpaceDir(lightDir)之类函数的原因,正是要把光转换到object space.
参考:http://blog.csdn.net/damenhanter/article/details/22481563