【问题标题】:Maintaining rotation during Quaternion normalization在四元数归一化期间保持旋转
【发布时间】:2013-09-13 16:03:07
【问题描述】:

我一直在为即将进行的项目研究四元数,但遇到了一个我无法解决的概念问题。

对一个四元数进行归一化的方法如下:

q_mag = sqrt(q0^2+q1^2+q2^2+q3^2)
q0 = q0/q_mag  
q1 = q1/q_mag   
q2 = q2/q_mag  
q3 = q3/q_mag

直截了当,就像规范化任何其他向量一样。但我的问题是这种归一化方法如何保留相同的旋转信息。使用表示轴角表示的四元数的定义,如下所示,

angle = 2 * acos(q0)
x = qx / sqrt(1-q0*q0)
y = qy / sqrt(1-q0*q0)
z = qz / sqrt(1-q0*q0)

由于标准化操作对 x、y、z 值进行了同等缩放,因此您旋转的轴永远不会改变。但是角度本身的值会随着归一化操作而发生剧烈变化。

那么使用保留 q0 的值并仅调整其他点以达到归一化的方法不是更有意义吗?

【问题讨论】:

  • 如果回答对您有帮助,您可能希望接受,否则请告诉我们可能仍不清楚的地方!

标签: quaternions


【解决方案1】:

数学答案:单位四元数表示 3D 空间中的旋转。任何其他(即:非单位)四元数不代表旋转,因此公式 angle = 2 * acos(q0) 不适用于这些四元数。所以标准化时角度没有变化,因为您要标准化的四元数一开始并不代表旋转。

编程答案:浮点运算存在精度问题。这些问题会导致小错误,如果累积起来可能会变成大错误。当两个单位四元数相乘时,数学结果是另一个单位四元数。然而,单位四元数乘法的浮点实现可能会导致四元数的范数接近 1 但不等于 1。在这种情况下,我们将对四元数进行归一化以纠正错误。当我们归一化时,我们将 q0 除以非常接近 1 的范数,因此 q0 的值没有重大变化。因为我们提前归一化,所以范数总是非常接近 1,我们不需要担心精度。

迟到的答案,但我希望它有所帮助。

【讨论】:

    【解决方案2】:

    我知道这有点像死神,抱歉,但我认为这可能对未来的读者有用。

    除非我完全弄错了,否则实际上最好不要在归一化时保留角度以考虑舍入误差(在使用四元数表示旋转的情况下,尤其是在游戏中)。让我解释一下原因:

    假设您有两个四元数(我将它们称为 Q1Q2 从这里开始)应该表示旋转,但由于舍入误差而不是单位,并且您想要将它们相乘(我将结果称为Q3。我们也希望这是一个单位四元数)。假设t1 是一个变量,当与Q1 的每个分量相乘时,Q1 成为一个单位四元数(这意味着t1 是一个除以Q1 的欧几里得长度,但这确实是在这里不相关。t2Q2 做同样的事情。如果我们现在乘以四元数后归一化(即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 的非实部如何不再有一个公因子这意味着以这种方式规范化Q3post-operation 可能会导致与规范化@ 时得到的四元数不同。 987654339@和Q1以这种方式预运行。

    对四元数进行归一化并不是一项廉价的操作,因此最好将非角度保持方式用于游戏之类的东西,因为您不需要经常使用它,尤其是在合成大量旋转时。我不确定其他四元数运算是否同样适用,但考虑到您可能会大量乘以四元数,至少在我看来,最好使用非角度保持方式。

    【讨论】:

    • 我们乘以四元数来组成旋转。游戏不是我的领域,但我想我们会乘以四元数来为当前的相机旋转添加更多旋转,例如,如果玩家移动鼠标看某个地方。这将按时间片发生一次,因此标准化会很便宜。繁重的操作是将旋转应用于场景中的所有对象(然后将它们投影到代表屏幕的 2D 平面)。但这不是四元数乘法,不需要归一化。我是在指出你的回答中的一个缺陷,还是我理解你的错误?
    • 我不确定我是否完全理解您的回复。我回答的重点是,如果你结合了很多旋转,你可以在相乘后使用非角度保持方法,并得到与在每一步标准化时相同的结果。角度保持方法并非如此,这会让我相信角度保持方法实际上可能会在您的角度中引入错误。
    • 即舍入误差会在角度中引入一个小误差,通过保留它,您也可以保留角度误差。考虑到这两种方法都不能完全消除舍入误差,我认为非角度保持方法更可取,因为它使用起来更便宜(每个对象只需要调用一次,而不是每次旋转调用一次)
    • 我的观点是:我不认为游戏需要很多轮换组合(q q)。它们确实需要大量矢量旋转 (q* v q),但这些不需要归一化。
    • 除上述之外,我认为我们没有选择何时进行正常化的奢侈。我们只需要单位四元数:每当我们将其中的 2 个相乘时,我们都会对结果进行归一化以解决操作期间的舍入误差。我也不确定为什么您认为存在“角度保持”和“非角度保持”归一化:如果四元数是非单位的,则实分量不代表旋转角度。在实践中,我们只是将每个组件除以规范。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多