美文网首页
【翻译】法线矩阵

【翻译】法线矩阵

作者: 诸葛飞 | 来源:发表于2020-09-18 17:27 被阅读0次

    在渲染中,有很多的计算是在视角空间中完成的。这是因为光照通常是在这个空间中计算的,否则,像一些依赖视角的效果,比如高光,将会比较难以实现。

    因此,我们需要一种方法将法线转换到视角空间。我们可以通过下面的写法把一个顶点转换到视角空间:

    vertexEyeSpace = gl_ModelViewMatrix * gl_Vertex;
    

    那么,我们为什么不能直接把这个应用到法线向量呢?首先,法线是一个3维向量,而ModelView矩阵是一个4x4矩阵;其次,因为法线是一个向量,所以我们只需要转换它的方向。ModelView矩阵左上方的3x3子矩阵包含了方向的信息,那么我们为什么不能使用这个子矩阵去转换法线呢?

    这可以通过下面的代码很简单的实现:

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

    但上面的代码只在部分情况下可以正常工作。

    让我们来看下一个潜在的问题:

    在上面的图中,我们看到一个带了一个法线和切线向量的三角形。在下面的图中,显示了如果ModelView矩阵包含了非均匀缩放会发生什么样的偏差。

    注意:如果是均匀缩放,那么法线的方向将会保持,虽然长度会受到影响,但可以简单的通过标准化修复。

    在上面的图中,ModelView矩阵应用到了所有的向量,包括法线,结果是显而易见的错误的:转换后的法线不再与表面垂直了。

    我们知道,一个向量可以表示为两个点之间的差异。比如切线向量,它可以通过计算三角形一条边上的两个顶点之间的差距来获得。如果P1P2是定义一条边的两个顶点,那么我们知道:

    T = P2 - P1

    如果把这个向量表示为包含4个元素且最后一个元素为0的元组,那么我们可以把这个等式两边都乘以ModelView矩阵

    T * ModelView = (P2 - P1) * ModelView

    结果是

    T * ModelView = P2 * ModelView - P1 * ModelView
    T' = P'2 - P'1

    因为P'1P'2为转换后的三角形的顶点,所以T'仍然与三角形的边相切。因此,ModelView保持了切线。但它却没有保持法线。

    使用和T向量一样的方法,我们可以找到两个点Q1Q2,让以下等式成立

    N = Q2 - Q1

    主要的问题是,就如上面的图所展示的那样,由转换后的的点定义的向量,Q2 - Q1,不一定仍然与边垂直。法线向量不是如切线向量那样,定义为两个点之间的差距,它定义为垂直于一个表面的向量。

    现在我们知道了,我们不能在所有情况下使用ModelView来转换法线向量。那么我们应该使用什么样的矩阵呢?

    假设G为一个3X3的矩阵,让我们看看如何计算它来正确的转换法线向量。

    我们知道,在矩阵转换之前,因为切线和法线向量是垂直的,所以T.N = 0。我们也知道,转换之后,它们也一定要垂直,所以N'.T'也一定要等于0。我们把ModelView的左上方的3x3矩阵称为M矩阵,T可以安全的乘以MT是一个向量,所以w元素是0).

    我们假设G是正确转换法线向量N的矩阵,那么就有了下面的等式

    N'.T' = (GN).(MT) = 0

    把点乘转换为叉乘,那么

    (GN).(MT) = (GN)T * (MT)

    注意为了叉乘向量,第一个向量的转置是必须的。我们知道两个矩阵相乘的转置,等于转置后矩阵的相乘,但顺序要相反,因此:

    (GN)T * (MT) = NTGTMT

    我们前面已经说过了NT的点乘是0,所以如果

    GTM = I

    那么我们有

    N'.T' = N.T = 0

    这正是我们要的,所以我们可以根据M来计算G

    GTM = I <==> G = (M-1)T

    因此M矩阵的逆矩阵的转置,是正确转换法线的矩阵。

    前面我们说直接使用ModelView矩阵在部分情况下可以正常工作。当ModelView左上方的3x3矩阵是正交矩阵的时候,我们有:

    M-1 = MT ==> G == M

    这是因为正交矩阵的转置与逆矩阵是一样的。那么什么是正交矩阵呢?正交矩阵就是矩阵的每行/列都是单位长度,并且互相垂直的矩阵。这意味这两个向量,被正交矩阵转换前后,它们之间的角度是一样的,因此转换后的法线依然垂直于切线。此外,它还保持了向量的长度。

    那么我们如何保证M是正交的呢?只要我们限制我们的几何变换仅限于旋转和位移,比如在OpenGL程序中我们仅仅使用glRotateglTranslate,不使用glScale,那么可以确保M是正交的。注意:gluLookAt也创建了一个正交矩阵。

    相关文章

      网友评论

          本文标题:【翻译】法线矩阵

          本文链接:https://www.haomeiwen.com/subject/eimjyktx.html