在早期版本的opengl中,在顶点着色器中有个内建的法线矩阵gl_NormalMatrix,因为GLSL 1.4版本之后这个内建变量就被删除了,所以这个工作就需要我自己去做了,今天我们就来讨论这个法线矩阵的推导过程。
首先这个法线矩阵是干什么的呢?我们先来说说光照计算,通常情况下会在两种坐标系下计算光照:观察坐标系和世界坐标系,当然人们会选择在观察坐标系下去计算,在观察坐标系下计算会更简单。比如漫反射和镜面放射,他们都需要法线,看图:
但是法线一般是在物体局部坐标系下计算的,所以我们需要把它变换到观察坐标系,由于法线只是代表方向的向量,平移对他没有意义,所以我们会去掉平移量,应该是这样做的:
view * model * vec4(aNormal, 0.0);
看起来貌似没什么问题,但是注意上面那句代码只有在模型没有经过非等比缩放才会正常工作,一旦模型经过非等比缩放,法线就会出现问题,在等比缩放时法线也会跟着一起缩放,我们只需要将其归一化即可,其实法线向量还是垂直于表面的,
即T点N乘等于零。如图:
但是一旦有非等比缩放,法线就会不一定还垂直于当前表面了,他可能会变成这样:
其中T为三角面的切线向量,N为法线向量
现在假设切线向量变换矩阵为M,变换后的切线向量T' = M * T,同样的我们假设现在有一个正确法线变换矩阵G,使得变换后的法线N' = G * N,那么变换后,N'点乘T'依然是等于零的,于是我们可以等到等式:
由于向量的点乘等价于向量的乘积(可以把转置的向量看做一个NX1列的矩阵):
又由于乘积的转置等于转置的乘积可得:
由于:
可得:
于是就得出了:
即法线变换矩阵等于观察变换矩阵逆的转置:
transpose( inverse( view * model ) ) * vec4(aNormal,0.0);