法线矩阵的推导

首先明确一点,法线矩阵是计算法线变换的矩阵,使得新的法线仍垂直于原来的平面。因为模型矩阵转化物体到世界坐标时,除了平移和均匀缩放,都可能破坏原法线的垂直性,比如将一个cube绕x轴旋转30度,原来的法线仍在y平面和z平面上,但物体表面已经不再原位置上了,这时我们需要把原法线也绕x轴旋转30度才能保持他们仍是原表面的法线。

至于为什么提到是“变换”矩阵的逆转置,原则上只有模型矩阵会破坏法线垂直性,但有时我们需要在别的空间计算,比如观察空间,view * model此时就是我们的变换矩阵M,可以把他整体当做一个模型矩阵,因为模型矩阵包含其中,可能破坏法线垂直性。

接下来我们推导法线矩阵(假设向量nnvv都是3x1列向量):

(1) 我们有法线向量nn和切线向量vv

nv=0 n \cdot v = 0

(2) 假设变换后的法线为n’,那么

nv=0 n' \cdot v' = 0

这里需要提及一个转换,矩阵乘法和点乘的转换,靠转置实现:

nv=0=>nTv=0 n \cdot v = 0 => n^T * v = 0

(3) 那么(2)可以转化为矩阵乘法

nTv=0 n'^T * v' = 0

(4) 假设法线矩阵为MM',那么

n=Mn n' = M' * n

(5) 切线通过变换矩阵MM变换得到vv'

v=Mv v' = M * v

(6) 将上面的等式代入(3),全部转化为矩阵乘法(后面不再写符号)

nTv=(Mn)T(Mv)=0 n'^T * v' = (M' * n)^T * (M * v) = 0

把它完全展开:

nTMTMv=0 n^TM'^TMv = 0

因为

nTv=0 n^Tv = 0

所以

MTM=λI M'^TM = \lambda I

我们最终只需要垂直关系,不受比例因子影响,将λ\lambda代入1得

MT=M1=>M=(M1)T M'^T = M^{-1} => M' = (M^{-1})^T

所以我们的法线矩阵就是变换矩阵逆的转置

M=(M1)T M' = (M^{-1})^T

在OpenGL中,我们常常在着色器中这样计算法线矩阵:

1
Normal = mat3(transpose(inverse(model))) * aNormal;