Normal Matrix(法向量变换矩阵)

我们都知道gl的坐标系统。它的工作是将坐标从一个坐标系转到另一个坐标系。其中我们用到了几个转换矩阵。其中最为重要的是模型(Model)、视图(View)、投影(Projection)三个矩阵。因为涉及光线光照部分的计算通常都在eye space中进行计算,所以我们需要把坐标转换到世界空间(world space\eye space)中,否则基于眼睛位置的效果(比如镜面反射)就很难实现。一般通过以下代码将vertex到 eye space(world space):

vertexEyeSpace = gl_ModelViewMatrix * gl_Vertex;

为什么我们不能对法向量(normal vector)进行同样的运算来转换到 eye space 呢?首先,法向量(normal vector)是一个三维向量,而 ModelView 是一个 44 的矩阵。其次,因为法向量代表方向,我们想要做的就是将该方向变换到 eye space 中。那么我们是否可以直接用modelView左上角的 33 矩阵来做这个变换呢?如果可以,我们只需要用下面的代码就可以完成变换:

normalEyeSpace = vec3(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));

很遗憾,上面的变换只适用于某些情况。这也是因此我们引入了 gl_NormalMatrix 的原因。
我们先来推导下gl_NormalMatrix:
首先我们来看下下面这张图:


Normal Matrix(法向量变换矩阵)_第1张图片

其中N是我们的法向量,T是三角形的切向量。那么我们想要求的gl_NormalMatrix应该满足变换前后方向不变。假设变换后的切向量为T',变换后的法向量为N'。所以应该满足:
T' * N' = T * N = 0。
下面是推导过程:
c代表因为,s代表所以:

c:
T = (P2 - P1)
s:
ModelView * T = ModelView * (P2 - P1) = ModelView * P2 - ModelView * P1 = P2' - P1'
 => ModelView * T = T'
c:
N' =  NormalMatrix * N
T' = ModelView * T
T' * N' = T * N = 0
s:
(NormalMatrix * N) · (ModelView * T) = 0
=>
transpose(NormalMatrix * N) * (ModelView * T)
transpose(N) * transpose(NormalMatrix) * ModelView * T = 0
c:
N * T = 0
s:
 transpose(NormalMatrix) * ModelView = I
=> NormalMatrix = transpose((ModelView)^(-1))

即NormalMatrix是ModelView矩阵逆的转置。

我们也可以看到,当M(ModelView)矩阵为正交矩阵时(即M的转置等于M的逆)时,法向量变换阵(NormalMatrix)等于M阵。这就是上文所说的特例。

重要结论:
NormalMatrix是ModelView矩阵逆的转置

参考:
http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/

你可能感兴趣的:(Normal Matrix(法向量变换矩阵))