OpenGL中法线矩阵的证明

2019-12-16  本文已影响0人  constantine丶

首先如果不使用法线矩阵,那么你可能会这样处理法向量

Normal = mat3(model) * aNormal;

大多数情况下,这是没有问题的,比如你只用到了位移和旋转变换,但是如果你使用了放缩(scale)就可能出现问题。


normalmat1.gif

在上图中,我们看到了一个三角形,其中包含法线和切线向量。
下图显示了当模型视图矩阵包含不均匀比例时发生的情况。


normalmat2.gif
例如三角形顶点的坐标为(0,10,0,1),(0,0,0,1) ,(10,0,0,1) 法向量为(1,1,0)
放缩变换的矩阵为

(1 0 0 0
0 2 0 0
0 0 1 0
0 0 0 1) -> 顶点变为(0 , 20 , 0 , 1) (0,0,0,1) (10,0,0,1)
对于法向量 就会变成 (1,2,0),所以这个法向量显然是错的嘛...

于是OpenGL中对于法线的处理有这么一条语句

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

它的意思是 模型矩阵左上角的逆矩阵的转置矩阵,即法线矩阵
对这个矩阵进行变换,
(1 0 0 0
0 2 0 0
0 0 1 0
0 0 0 1)
->
(1 0 0 0
0 1/2 0 0
0 0 1 0
0 0 0 1)
那么这一次,法线会变成 (1,1/2,0)这个结果是正确的,非常神奇!

补充一下线性代数的前置知识

逆矩阵(Inverse Matrix): AB=BA=E,E为单位矩阵,那么B为A的逆矩阵
转置矩阵(Transpose Matrix):把A矩阵的行与列的元素互换
转置矩阵的运算性质参考

image.png
1、乘积
用于矩阵相乘,表示为C=A * B,A的列数与B的行数必须相同,C也是矩阵,
2、点积
用于向量相乘,表示为C=A . B,A与B均为向量,

法线矩阵的推导过程

假设矩阵G是转换法线向量的正确矩阵。有:
(符号的意思结合上图来看,转换后的T' 和 N‘ 的点乘应该为0)


image.png

点积可以转换为矩阵的乘机,即把前面的向量转置,因此:
这里的N,T代表的向量,GN,MT的结果也为向量


image.png
image.png

因此如果,我们设:


image.png
则:
image.png
所以,(I为单位矩阵,即 NT * I * T = 0):
image.png

证毕

即使是对于着色器来说,逆矩阵也是一个开销比较大的运算,因此,只要可能就应该避免在着色器中进行逆矩阵运算,它们必须为你场景中的每个顶点都进行这样的处理。用作学习目这样做是可以的,但是对于一个对效率有要求的应用来说,在绘制之前你最好用CPU计算出法线矩阵,然后通过uniform把值传递给着色器(像模型矩阵一样)。

参考资料:
http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
https://learnopengl-cn.github.io/02%20Lighting/02%20Basic%20Lighting/

上一篇下一篇

猜你喜欢

热点阅读