我知道这有点像死神,抱歉,但我认为这可能对未来的读者有用。
除非我完全弄错了,否则实际上最好不要在归一化时保留角度以考虑舍入误差(在使用四元数表示旋转的情况下,尤其是在游戏中)。让我解释一下原因:
假设您有两个四元数(我将它们称为从这里开始) Q1
,Q2
它们应该代表旋转,但由于舍入误差而不是单位,并且您想将它们相乘(我将调用结果Q3
. 我们也希望这是一个单位四元数)。假设t1
是一个变量,当与 的每个分量相乘时Q1
,它Q1
变成一个单位四元数(这意味着t1
一个除以 的欧几里得长度Q1
,但这在这里真的不相关。t2
对 做同样的事情Q2
。如果我们现在将四元数后归一化(即Q3 = (t1*Q1)(t2*Q2)
)我们得到以下内容:
Q3.w = t1*Q1.w*t2*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = t1*Q1.w*t2*Q2.x + t1*Q1.x*t2*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = t1*Q1.w*t2*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*t2*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = t1*Q1.w*t2*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*t2*Q2.w
可以重写为
Q3.w = (t1*t2)*(Q1.w*Q2.w - Q1.x*Q2.x - Q1.y*Q2.y - Q1.z*Q2.z)
Q3.x = (t1*t2)*(Q1.w*Q2.x + Q1.x*Q2.w + Q1.y*Q2.z - Q1.z*Q2.y)
Q3.y = (t1*t2)*(Q1.w*Q2.y - Q1.x*Q2.z + Q1.y*Q2.w + Q1.z*Q2.x)
Q3.z = (t1*t2)*(Q1.w*Q2.z + Q1.x*Q2.y - Q1.y*Q2.x + Q1.z*Q2.w)
换句话说,Q3=(t1*Q1)(t2*Q2)=(t1*t2)(Q1*Q2)
。如您所见,在乘法之后以这种方式归一化会产生与对两个输入预乘法进行归一化相同的四元数。这意味着我们只需在将旋转应用于向量/网格/点之前进行归一化,而不是在每次计算之后,因为无论四元数偏离单位多远,它都会产生相同的结果。
现在让我们看一下相同的计算,但是使用保留角度的方式来制作四元数单元(t
变量现在仅与非实数(又名 xyz)部分相乘时构成四元数单元):
Q3.w = Q1.w*Q2.w - t1*Q1.x*t2*Q2.x - t1*Q1.y*t2*Q2.y - t1*Q1.z*t2*Q2.z
Q3.x = Q1.w*Q2.x + t1*Q1.x*Q2.w + t1*Q1.y*t2*Q2.z - t1*Q1.z*t2*Q2.y
Q3.y = Q1.w*Q2.y - t1*Q1.x*t2*Q2.z + t1*Q1.y*Q2.w + t1*Q1.z*t2*Q2.x
Q3.z = Q1.w*Q2.z + t1*Q1.x*t2*Q2.y - t1*Q1.y*t2*Q2.x + t1*Q1.z*Q2.w
注意 的非实部如何Q3
不再具有共同因子这意味着Q3
以这种方式规范化后期操作可能会导致与您在规范化Q2
和Q1
以这种方式预操作时得到的四元数不同。
归一化四元数并不是一个便宜的操作,因此最好将非角度保留方式用于游戏等内容,因为您需要较少使用它,尤其是在合成大量旋转时。我不确定其他四元数运算是否同样适用,但考虑到您可能会大量乘以四元数,至少在我看来,最好使用非角度保持方式。