6

根据 OpenGL 红皮书,附录 F,可以使用常规 3D 变换矩阵 M 来计算法线向量上的动作:

normalTransformed = transpose(inverse(M)) * normal

然而,虽然与变换法线相关的正交平面确实平行于变换后的表面,但变换后的法线向量本身可能指向与我预期相反的方向,即“进入”表面而不是“出表面。

如果我希望 normalTransformed 指向正确的方向(即,与它所连接的表面未变换时指向的方向相同),我应该如何在数学上做到这一点?

例子

假设我的表面法线是 (0,0,1),我的变换是在 Z 方向上平移 10。变换矩阵 M 为:

1 0 0 0
0 1 0 0
0 0 1 10
0 0 0 1

然后转置(逆(M))是:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 -10 1

应用于表面法线 (0,0,1),即齐次坐标中的 (0,0,1,1),得到:

normalTransformed = (0, 0, 1, -9)

从齐次坐标返回:

(0, 0, -1/9)

归一化为长度 1:

(0, 0, -1)

与原始法线向量 (0, 0, 1) 相比,它指向相反的方向。

4

4 回答 4

19

应用于曲面法线 (0,0,1),即齐次坐标中的 (0,0,1,1)

好,就停在那里。

如果您要将表面法线视为齐次坐标,则使用作为 W 分量,而不是 1。现在,您可能很快就会意识到您不能除以零,但这也是您不使用的原因不要对法线做齐次数学。

法线不是位置;这是一个方向。方向没有位置,因此翻译它们是没有意义的。W=0 的同质位置代表无限远的“位置”(这就是为什么你不能划分它们)。一个无限远的位置离每一个有限点都无限远。

因此,无限远的位置是一个方向:无论您从哪个(有限)位置看它,它都不会改变方向。

现在,如果你有一个 4x4 矩阵并且需要用它来转换法线,你只需要使用 W=0,因为它可以使数学计算出来。它摆脱了矩阵的平移分量。应完全忽略转换后的 W 分量。

因此,转换后,您会得到:

normalTransformed = (0, 0, 1, -9)

忽略 W 分量后,变为:

normalTransformed = (0, 0, 1)


更有可能的是,您的法线实际上并没有从一开始就指向正确的方向。当然,在没有代码和数据的情况下,可以说的不多,但是假设输入是合法的,那么数学是可行的。

另外,不要在着色器中进行反转/转置。在 CPU 上执行此操作并将生成的矩阵传递给着色器。

于 2012-05-15T09:23:32.527 回答
2

问题是你正在除以你的w坐标,就好像你的法线是一个点。(当 时w<0,这个除法是颠倒你的法线。)相反,你需要完全忽略w-coordinate:完全放弃它,而不是除以它。

您的法线不是一个点,它在技术上是一个协向量(这就是为什么它与点和向量的转换方式不同)。它实际上没有w-coordinate - 添加一个的唯一原因是为了方便使用现有的 4x4 矩阵例程。

如果确实添加了任意w坐标,则具有给定法线的平面的齐次坐标。像法线一样,这样的平面是通过用于变换点的矩阵的逆转置来变换的(并且,请注意,将平面除以其w-坐标是没有意义的——平面也不是点! )。

如果法线是从三角形派生的,则三角形的平面应该具有该法线 - 但是,法线明确缺少w确定确切平面的坐标。将任意平面添加w到法线(无论是01还是其他)意味着选择具有该法线的任意平面,因此对其进行变换将产生具有变换后的法线的任意平面;这就是为什么您需要忽略w使用 4x4 矩阵进行转换后的原因。

于 2012-05-15T23:17:59.197 回答
1

如果您应用的仿射变换反转了坐标系的“手性”,您应该只在法线的相对方向上反转。例如,如果您按比例缩放,就会发生这种情况[1, 1, -1]

根据Physically Based Rendering一书,您可以通过计算左上角 3x3(正常?)矩阵的行列式来检查这种情况。如果行列式为负,则矩阵将改变惯用手,您应该反转法线。

[我昨天刚读到这个,我从记忆中引用这个]。

于 2014-05-27T16:00:41.487 回答
1

Nicol Bolas在他的回答中写的是绝对正确的,确实我不会重复这些概念。

但是我在问题中指出了一些有趣的观点。

首先,法线矩阵通常定义为模型视图矩阵左上角 3x3 矩阵的逆矩阵的转置。这是因为法线不是使用齐次位置定义的,实际上不需要 4x4 矩阵;如果您想使用整个模型视图矩阵,请遵循Nicol Bolas的方向,但数学保持不变。(因为 w为零)。

其次,你已经说过

我希望 normalTransformed 指向正确的方向(即,与它所连接的表面未变换时指向的方向相同),我应该如何在数学上做到这一点?

法线矩阵用于与模型变换相干地变换法线(实际上法线矩阵是从模型视图矩阵导出的)。正如我从你的引文中可以理解的那样,你想要正常的不被改变......事实上,你为什么要改变它?您可以直接使用“正常”。

于 2012-05-15T12:33:22.260 回答