我们都知道gl的坐标系统。它的工作是将坐标从一个坐标系转到另一个坐标系。其中我们用到了几个转换矩阵。其中最为重要的是模型(Model)、视图(View)、投影(Projection)三个矩阵。因为涉及光线光照部分的计算通常都在eye space中进行计算,所以我们需要把坐标转换到eye space中,否则基于眼睛位置的效果(比如镜面反射)就很难实现。一般通过以下代码将vertex到 eye 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:
首先我们来看下下面这张图:
其中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 //因为N与T点积为0,也就是transpose(N)*T为0(点积相当于转置一个向量后乘以另外一个向量),所以上面式子中间部分为单位矩阵,因为向量乘以单位矩阵等于自身,即transpose(NormalMatrix)*ModelView=单位矩阵I 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/
作者:雨幻逐光
链接:https://www.jianshu.com/p/e001aec29976
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 标签:Matrix,Normal,ModelView,矩阵,transpose,向量,gl,NormalMatrix From: https://www.cnblogs.com/DvsJ/p/16813888.html