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

Posted

技术标签:

【中文标题】在顶点着色器中将法线转换为视图空间【英文标题】:Transforming normal to view space in Vertex Shader 【发布时间】:2013-07-01 10:10:44 【问题描述】:

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

// normalMatrix is retrieved from GLMatrixStack modelViewMatrix
vec3 vEyeNormal = normalMatrix * vNormal

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

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)));

我意识到:

法线矩阵只是模型视图矩阵的旋转分量,因为 法线向量的平移是不可接受的。 OpenGL 操作的顺序是缩放、平移、旋转 (Opengl order of matrix transformations) 逆矩阵是撤消最后一次转换 (http://tomdalling.com/blog/modern-opengl/04-cameras-vectors-and-input/)

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

【问题讨论】:

【参考方案1】:

你的假设并不完全正确。

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

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

逆矩阵是撤消上一次变换。

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

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

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

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

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

【讨论】:

感谢您在我的想法中发现错误以及简单实用的答案。【参考方案2】:

根据《3D 游戏编程和计算机图形学的数学》第 66 页的答案(作者 Eric Lengyel):

曲面上特定点处的切线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(N) * T = N . T = 0

所以如果满足上述条件:

trans(G) * M = I

出处:

G = trans(inv(M))

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

【讨论】:

如果我很好理解切向量 (T) 总是垂直于曲面以将其推广到不同形状的曲面,而矩阵 M 用于变换向量 T、N 和该曲面的顶点? @CppMonster:不,法线向量总是垂直于表面(根据定义)。假设表面是一个多边形网格,那么 M 可以用来变换顶点和切向量,但不能用来变换法向量。要转换法线向量,需要使用 M 的倒数的转置,也就是上面所说的。 我匆忙写错了(显然 N 垂直于表面,它是这个线程的基础)。我想写向量 T 垂直于向量 N 以概括不同形状的表面(如果我对切线有很好的理解)。感谢您提供给我的信息,因为它有用且有价值。

以上是关于在顶点着色器中将法线转换为视图空间的主要内容,如果未能解决你的问题,请参考以下文章

渲染管道几何阶段二“顶点着色器”

在顶点着色器中定位顶点后如何更新法线?

我可以使用顶点着色器来显示模型法线吗?

如何在 OpenGL ES 2.0 中将视图/模型/投影矩阵传递给我的顶点着色器?

验证顶点着色器中变换矩阵的使用。正确性或法线变换

GLSL法线向量变换