【发布时间】:2012-11-19 05:10:53
【问题描述】:
我正在处理一些着色器,我需要转换法线。
我在几个教程中读到了变换法线的方式是将它们与模型视图矩阵的逆矩阵的转置相乘。但我找不到解释为什么会这样,这背后的逻辑是什么?
【问题讨论】:
标签: opengl glsl game-engine game-physics
我正在处理一些着色器,我需要转换法线。
我在几个教程中读到了变换法线的方式是将它们与模型视图矩阵的逆矩阵的转置相乘。但我找不到解释为什么会这样,这背后的逻辑是什么?
【问题讨论】:
标签: opengl glsl game-engine game-physics
它源于法线的定义。
假设您有法线N 和一个向量V,这是一个与法线在对象上相同位置的切线向量。然后根据定义N·V = 0。
切线向量与物体表面的方向相同。因此,如果您的表面是平面的,则切线是对象上两个可识别点之间的差异。因此,如果V = Q - R 其中Q 和R 是表面上的点,那么如果您通过B 变换对象:
V' = BQ - BR
= B(Q - R)
= BV
通过考虑限制,同样的逻辑适用于非平面表面。
在这种情况下,假设您打算通过矩阵B 转换模型。所以B 将应用于几何。然后要弄清楚如何处理您需要为矩阵求解的法线,A 以便:
(AN)·(BV) = 0
将其转换为行与列以消除显式点积:
[tranpose(AN)](BV) = 0
把转置拉到外面,去掉括号:
transpose(N)*transpose(A)*B*V = 0
这就是“法线的转置”[product with]“已知变换矩阵的转置”[product with]“我们正在求解的变换”[product with]“表面上的向量模型" = 0
但我们首先声明 transpose(N)*V = 0,因为这与声明 N·V = 0 相同。所以为了满足我们的约束,我们需要表达式的中间部分——transpose(A)*B——消失。
因此我们可以得出结论:
transpose(A)*B = identity
=> transpose(A) = identity*inverse(B)
=> transpose(A) = inverse(B)
=> A = transpose(inverse(B))
【讨论】:
A 转换模型”对我来说似乎很清楚。您的问题暗示了我以错误的方式口头描述了 A 和 B。
B是模型变换矩阵,我们怎么知道切线V需要乘以它而不是不是正常的N?
我最喜欢的证明如下,其中 N 是法线,V 是切向量。由于它们是垂直的,它们的点积为零。 M 是任何 3x3 可逆变换 (M-1 * M = I)。 N'和V'是经过M变换的向量。
为了获得一些直觉,请考虑下面的剪切变换。
请注意,这不适用于切向量。
【讨论】:
看看这个教程:
https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html
您可以想象,当球体的表面拉伸(因此球体沿一个轴或类似的东西缩放)时,该表面的法线将全部“弯曲”到彼此。事实证明,您需要反转应用于法线的比例来实现这一点。这与使用逆转置矩阵进行变换相同。上面的链接显示了如何从中导出逆转置矩阵。
还要注意,当比例统一时,您可以简单地将原始矩阵作为普通矩阵传递。想象一下同一个球体沿所有轴均匀缩放,表面不会拉伸或弯曲,法线也不会。
【讨论】:
如果模型矩阵由平移、旋转和缩放组成,则不需要进行逆转置来计算法线矩阵。只需将法线除以平方比例并乘以模型矩阵,我们就完成了。您可以将其扩展到具有垂直轴的任何矩阵,只需计算您正在使用的矩阵的每个轴的平方比例。
详情我写在我的博客里:https://lxjk.github.io/2017/10/01/Stop-Using-Normal-Matrix.html
【讨论】:
不明白为什么在与模型矩阵相乘之前不将方向向量的第 4 个元素归零。不需要反转或转置。将方向向量视为两点之间的差。将这两个点与模型的其余部分一起移动 - 它们与模型的相对位置仍然相同。取两点之差得到新方向,第四个元素抵消为零。便宜很多。
【讨论】: