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

Cpp*_*ter 3 c++ opengl matrix

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

// normalMatrix is retrieved from GLMatrixStack modelViewMatrix
vec3 vEyeNormal = normalMatrix * vNormal
Run Code Online (Sandbox Code Playgroud)

我想在不使用 GLT 库的情况下编写程序。在另一个来源(http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Diffuse_Reflection)中,我发现了以下公式:

vec3 normalDirection = normalize(m_3x3_inv_transp * v_normal);
Run Code Online (Sandbox Code Playgroud)

变量 m_3x3_inv_transp 计算如下:

glm::mat3 m_3x3_inv_transp = glm::transpose(glm::inverse(glm::mat3(mesh.object2world)));
Run Code Online (Sandbox Code Playgroud)

我意识到:

我的问题是为什么在反转和转置矩阵后我得到 NormalMatrix 以及如何通过反转计算来检查它?

Nic*_*ler 6

你的假设并不完全正确。

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

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

逆矩阵是撤销最后一次变换。

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

法线矩阵只是模型视图矩阵的旋转分量。

不。如果是这种情况,那么您可以丢弃矩阵的平移(和任何透视)部分。但事实并非如此。

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

对于一般矩阵,您必须按照您的说明计算矩阵。想象一下按 (1, 2) 缩放。如果你变换一个圆,它就会变成一个椭圆。让我们看看 45° 处的法线。该位置的圆的法线是 (1, 1)(未标准化)。如果我们用缩放矩阵变换这个法线,我们得到 (1, 2)。如果您想象变换后的椭圆,您将看到法线不再与表面正交。因此,您必须使用不同的变换(在这种情况下,按 (1, 0.5) 进行缩放)以保持正交性。