0

我有一个简单的四元数实现对象旋转。如果我创建两个四元数表示围绕相同的轴对齐向量(即沿 X、Y 或 Z 轴)的旋转,则结果与通过它们的大小之和的单个旋转相同(即旋转 PI/2 然后 PI /2 再次与 PI 旋转相同)。那挺好的。

一旦旋转轴未与轴对齐,则串联会偏离预期(按 PI/2 旋转,然后 PI/2 再次按 PI 旋转不同)。这不好。

在仔细研究了我的代码几天后,我没有发现任何问题,所以现在让我问一下:我是否在某种程度上从根本上误解了四元数的工作原理?我根据它们所代表的轴角旋转来推理四元数,因为坦率地说,我并不完全理解四元数。

如果没有,你能看看我的代码吗?:-) 我只是将整个东西(用 Java 编写——我的目标是 Android)推送到 GitHub: https ://github.com/wtracy/quaternions 在 Quaternions 目录下是一个 Eclipse 项目。(您不需要 Eclipse 来读取任何内容,但它很方便。)四元数类位于 src/ 文件夹下。在 test/ 文件夹中是运行我的 Quaternion 类所需的类的 JUnit 测试和存根。

我已尽力使我的代码和测试易于理解。我觉得要求互联网在我的代码中查找错误感到愚蠢,但我没有想法。:-P

4

2 回答 2

3

您的四元数乘法中有符号错误。

public Quaternion times(Quaternion q2) {
    Quaternion q1 = this;
    float w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z;
    float x = q1.x*q2.w + q1.w*q2.x + q1.z*q2.y - q1.y*q2.z;
    float y = q1.w*q2.y - q1.x*q2.z + q1.y*q2.w + q1.z*q2.x;
    float z = q1.w*q2.z - q2.x*q2.y + q1.y*q2.x + q1.z*q2.w;
    return new Quaternion(w, x, y, z);
}

写出来的产品是

(w1 + x1*i + y1*j + z1*k)*(w2 + x2*i + y2*j + z2*k)
= w1*w2 - x1*x2 - y1*y2 - z1*z2
+ (w1*x2 + x1*w2 + y1*z2 - z1*y2)*i
+ (w1*y2 - x1*z2 + y1*w2 + z1*x2)*j
+ (w1*z2 + x1*y2 - y1*x2 + z1*w2)*k

自从

i*j = k    j*i = -k
j*k = i    k*j = -i
k*i = j    i*k = -j

你在方程中有一个减号的错误术语xz- 如果两个轴相同,那不会有什么不同,因为你也可以写(作为速记)

(r + v)*(s + w) = r*s - <v|w> + r*w + s*v + v×w

对于共线向量,v×w = 0但如果轴不同,它会显示出来。

此外,在等式中z

float z = q1.w*q2.z - q2.x*q2.y + q1.y*q2.x + q1.z*q2.w;
                          ^^^^^^^^^

你有一个错字,q2对这两个因素都使用一次。

它应该是

public Quaternion times(Quaternion q2) {
    Quaternion q1 = this;
    float w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z;
    float x = q1.x*q2.w + q1.w*q2.x - q1.z*q2.y + q1.y*q2.z;
    float y = q1.w*q2.y - q1.x*q2.z + q1.y*q2.w + q1.z*q2.x;
    float z = q1.w*q2.z + q1.x*q2.y - q1.y*q2.x + q1.z*q2.w;
    return new Quaternion(w, x, y, z);
}
于 2012-12-21T00:24:28.847 回答
0

一旦旋转轴不是轴对齐的,那么串联就会偏离预期(旋转 PI/2 然后 PI/2 再次与旋转 PI 不同)。这不好。

即使你算对了,你仍然会发现情况并非如此。三维空间中的旋转一般是不可交换的。如果您先执行旋转 A,然后执行旋转 B,则通常最终会得到与先执行旋转 B 再执行旋转 A 不同的方向。

于 2012-12-21T12:31:38.347 回答