参考:法线贴图_洛阳李四的博客
闫神课上讲的关于法线贴图的定义和与位移贴图的区别已经很详细了,仅补充一些自己的理解和学习点。
法线贴图 Normal Mapping
一些基本的小理解:
(1)法线贴图是一张2D纹理,虽然有颜色,但储存的并不是RGB的值而是像素的法向量。法线贴图的值范围在[0,1]之间(作为RGB真实的值是[0,255],贴图里定义的范围[0,1]当真正作为颜色时会✖255)。由于大部分的法向量都是朝z轴正向的,即(0,0,1),也就是对应的蓝色通道B值为255,因此法线贴图一般都是一张蓝紫色的纹理。
(2)上面说到的法向量,可以模拟物体表面因为凹凸不平所产生的明暗效果,但只是在光照互动上做技巧,并没有改变高度(区别于高度贴图/位移贴图),因此对于不接受光照的物体,法线贴图是没用处的。
(3)要想把坐标系xyz下的某个法向量计入法线贴图,需要做一些变换,把在坐标中的[-1,1]范围变换成[0,1]。
物体顶点的原始信息
(1)空间法线 Normal,与物体表面垂直的向量
(2)空间切线 Tangent,与物体表面平行的向量,也与UV中的U有关,下面两张图能够简单的理解UV是什么和空间切线与UV的关系。图分别来自:
UnityShader 基础(27)-法线贴图-世界空间与切线空间法线计算 - 知乎 (zhihu.com)
【UE4】材质基础(一)——UV - 知乎 (zhihu.com)
世界空间 World Space
基于世界坐标的一种贴图,是三种里最不灵活的一种,模型本身不能发生旋转,仅适用于大型的、静态的模型,比如一些地形场景等。
模型空间 Object Space
切线空间 Tangent Space
当面对复杂物体表面时,切线空间法线贴图是最常用的一种,切线空间的法向量基于每个面的切线方向。
(1)切线空间可以理解成计算光照时真正用的z值坐标。
(2)切线空间是顶点构造的一个局部坐标系,位于表面之上,法线永远朝向正z方向,每个表面定义的切线空间是不一样的;
(3)我们可以计算出一个矩阵,矩阵X空间法向量就能得到切线空间的向量,这个矩阵就是——TBN矩阵。
TBN矩阵
TBN矩阵由切线tangent、副切线bitangent和法线normal向量组成,三向量两两正交:
(图来自:法线贴图和切线空间_SixDayCoder的博客)
其中副切线b和UV中的v平行,切线t和UV中的U平行。至于这个矩阵是如何得到的,可以参考games101作业3中给出的TBN矩阵的步骤。GAMES101作业3-填补代码框架学习过程_flashinggg的博客
...
// Let n = normal = (x, y, z)
// Vector t = (x*y/sqrt(x*x+z*z),sqrt(x*x+z*z),z*y/sqrt(x*x+z*z))
// Vector b = n cross product t
// Matrix TBN = [t b n]
float x = normal.x();
float y = normal.y();
float z = normal.z();
Eigen::Vector3f t, b;
t << x * y / std::sqrt(x * x + z * z), std::sqrt(x * x + z * z), z* y / std::sqrt(x * x + z * z);
b = normal.cross(t);
Eigen::Matrix3f TBN;
TBN <<
t.x(), b.x(), x,
t.y(), b.y(), y,
t.z(), b.z(), z;
...