C++ 在顶点着色器中将法线变换为视图空间

C++ 在顶点着色器中将法线变换为视图空间,c++,opengl,matrix,C++,Opengl,Matrix,当我们想要在顶点着色器中计算光时,我们需要视图空间中的法向量。一般情况下,如下所示(来自OpenGL Superbible 5): 我想在不使用GLT库的情况下编写程序。在另一个源()中,我找到了以下公式: vec3 normalDirection = normalize(m_3x3_inv_transp * v_normal); 变量m_3x3_inv_transp的计算如下: glm::mat3 m_3x3_inv_transp = glm::transpose(glm::inverse(

当我们想要在顶点着色器中计算光时,我们需要视图空间中的法向量。一般情况下,如下所示(来自OpenGL Superbible 5):

我想在不使用GLT库的情况下编写程序。在另一个源()中,我找到了以下公式:

vec3 normalDirection = normalize(m_3x3_inv_transp * v_normal);
变量m_3x3_inv_transp的计算如下:

glm::mat3 m_3x3_inv_transp = glm::transpose(glm::inverse(glm::mat3(mesh.object2world)));
我意识到:

  • 法线矩阵是modelview矩阵的唯一旋转组件,因为 法向量的平移是不可接受的
  • OpenGL操作的顺序是缩放、平移、旋转 ()
  • 逆矩阵是最后一个变换 ()

我的问题是,为什么在对矩阵进行求逆和转置后,我会得到法线矩阵,以及如何通过反向计算来检查它?

答案基于《3D游戏编程和计算机图形学数学》(Eric Lengyel著)第66页:

曲面上特定点的切线
T
和法线
N
必须垂直,因此:

N . T = 0
假设我们使用矩阵
M
变换曲面。变换曲面上点处的切线为:

T' = MT
我们想要找到一个矩阵
G
,使得
N'=GN
是变换曲面上点的法线。由于变换曲面上点的法线和切线必须仍然垂直,因此我们有:

0 = N' . T' = (GN) . (MT) = trans(GN) * MT = trans(N) * trans(G) * MT
现在:

因此,如果:

trans(G) * M = I
从那里:

G = trans(inv(M))

换句话说,变换法线所需的矩阵是用于变换切线的矩阵的逆矩阵的转置。

您的假设并不完全正确

OpenGL操作的顺序是缩放、平移、旋转

不,通常你可以有一个任意的世界矩阵。这可以包括任意数量的操作

逆矩阵是最后一个变换

不。如果你反转一个矩阵,它的整个效果都会恢复。例如,如果矩阵绕x轴旋转45°并平移(1,2,3),则其逆矩阵将平移(-1,-2,-3),然后绕x轴旋转-45°

法线矩阵是modelview矩阵的唯一旋转组件

不,如果是这样的话,那么你可以扔掉矩阵的翻译(和任何透视图)部分。但事实并非如此

法线矩阵用于变换法线,使其仍与相应曲面正交。对于刚体变换(即旋转和平移),可以直接使用世界变换。其中一个原因是可以通过转置旋转矩阵来反转旋转矩阵(因为它是正交的)。然后是
转置(transpose(world))
,它是原始矩阵


对于一般矩阵,必须按照说明计算矩阵。设想按(1,2)进行缩放。如果变换圆,它将变成椭圆。让我们看看45°的法线。该位置的圆法线为(1,1)(未标准化)。如果我们用缩放矩阵变换这个法线,我们得到(1,2)。如果你想象变换后的椭圆,你会发现法线不再与曲面正交。所以你必须使用不同的变换(在本例中是按(1,0.5)缩放),以保持正交性。

感谢我的思考中的错误和简单实用的答案。如果我很好地理解切向量(T)始终垂直于曲面,将其推广到不同形状的曲面,矩阵M用于变换向量T,N和该曲面的顶点?@CppMonster:不,法向量始终垂直于曲面(根据定义)。假设曲面是多边形网格,则可以使用M变换顶点和切线向量,但不能变换法向量。要变换法向量,需要使用M的倒数的转置,这就是上面所说的。我匆忙写错了(显然N垂直于曲面,这是这个线程的基础)。我想写向量T垂直于向量N,以推广不同形状的曲面(如果我对切线有很好的理解)。谢谢你给我的一条信息,因为它是有用和有价值的。
trans(G) * M = I
G = trans(inv(M))