根据OpenGL红皮书附录F,常规3D变换矩阵M可用于计算法向量上的动作:
normalTransformed = transpose(inverse(M)) * normal
然而,虽然与变换法线相关联的正交平面确实与变换曲面平行,但可能发生变换后的法向量本身指向与我期望的相反的方向,即'进入& #39;表面而不是'表面。
如果我希望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)相比,指向相反方向。
答案 0 :(得分:19)
应用于曲面法线(0,0,1),即均匀坐标中的(0,0,1,1)
好的,停在那儿。
如果您要将表面法线视为齐次坐标,则使用零作为W组件,而不是1.现在,您可能会很快意识到可以& #39; t除以零,但这也是你不能在法线上做同质数学的原因。
法线不是一个位置;这是一个方向。方向没有位置,因此翻译它们毫无意义。 W = 0的同质位置代表"位置"无限远(这就是为什么你不能分开它们)。无限远的位置与每个有限点无限远。
因此,无穷远处的位置是方向:无论你从哪个(有限)位置看,它都不会改变方向。
现在,如果你有一个4x4矩阵并且需要用它来变换法线,你只能使用W = 0,因为它可以解决数学问题。它摆脱了矩阵的平移分量。应完全忽略变换后的W分量。
因此,在转换之后,你会得到这个:
normalTransformed =(0,0,1,-9)
忽略W组件后,变为:
normalTransformed =(0,0,1)
更有可能的是,你的法线实际上并没有指向正确的方向。当然,在没有代码和数据的情况下,可以说更多,但数学运作假设输入是合法的。
另外,不要在着色器中进行反转/转置。在CPU上执行此操作并将生成的矩阵传递给着色器。
答案 1 :(得分:2)
问题是你要用w
坐标除以,就好像你的法线是一个点。 (当w<0
时,这个除法正在逆转你的法线。)相反,你需要完全忽略w
- 坐标:完全放弃它,而不是除以它。
你的法线不是一个点,它在技术上是一个covector(这就是为什么它与点和向量的转换不同)。它实际上没有w
- 坐标 - 添加一个的唯一原因是为了方便使用现有的4x4矩阵例程。
如果添加任意w
- 坐标,则具有给定法线的平面的齐次坐标。像法线一样,这样的平面是通过用于变换点的矩阵的逆转换而变换的(并且,注意将平面除以其w
- 坐标没有意义 - 平面不是一点,要么!)。
如果法线来自三角形,则三角形的平面应具有该法线 - 但是,法线明确缺少w
- 坐标,该坐标确切地确定了哪个平面。向正常添加任意w
(无论是0
,1
还是其他东西)意味着选择具有该法线的任意平面,因此对其进行变换将产生任意平面变换正常;这就是为什么在使用4x4矩阵进行转换后需要忽略w
的原因。
答案 2 :(得分:1)
Nicol Bolas 在他的回答中写的是绝对正确的,实际上我不会重复这些概念。
但我在问题中指出了一些可能有趣的观点。
首先,正常矩阵通常被定义为模型视图矩阵的左上3×3矩阵的逆的转置。这是因为法线不是使用齐次位置定义的,实际上不需要4x4矩阵;如果你想使用整个模型视图矩阵,请按照 Nicol Bolas 方向,但数学保持不变。 (因为 w 为零)。
其次,你已说过
我希望normalTransformed指向正确的方向(即 与其所在的表面指向的方向相同 附件没有改变),我应该怎样做,数学上?
法向矩阵用于通过模型变换相干地变换法线(事实上,法线矩阵是从模型视图矩阵导出的)。正如我从你的引言中可以理解的那样,你希望法线不被改变......的确,你为什么要改造它?你可以直接使用'normal'。
答案 3 :(得分:1)
如果要应用的仿射变换反转坐标系的“旋向性”,则只能在法线的相对方向上反转。例如,如果您按[1, 1, -1]
缩放,就会发生这种情况。
根据书籍基于物理的渲染,您可以通过计算左上3x3(正常?)矩阵的行列式来检查这种情况。如果行列式是负数,则矩阵将改变惯性,你应该反转法线。
[我昨天刚刚读到这篇文章,并从记忆中引用了这一点]。