“QQuaternion”旋转是如何工作的?

问题描述 投票:0回答:1

我注意到 Qt 库和其他库之间通过四元数进行向量旋转的差异。

这是Qt的实现。

QQuaternion QQuaternion::fromEulerAngles(float pitch, float yaw, float roll)
{
    // Algorithm from:
    // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60

    pitch = qDegreesToRadians(pitch);
    yaw = qDegreesToRadians(yaw);
    roll = qDegreesToRadians(roll);

    pitch *= 0.5f;
    yaw *= 0.5f;
    roll *= 0.5f;

    const float c1 = std::cos(yaw);
    const float s1 = std::sin(yaw);
    const float c2 = std::cos(roll);
    const float s2 = std::sin(roll);
    const float c3 = std::cos(pitch);
    const float s3 = std::sin(pitch);
    const float c1c2 = c1 * c2;
    const float s1s2 = s1 * s2;

    const float w = c1c2 * c3 + s1s2 * s3;
    const float x = c1c2 * s3 + s1s2 * c3;
    const float y = s1 * c2 * c3 - c1 * s2 * s3;
    const float z = c1 * s2 * c3 - s1 * c2 * s3;
}

这是一些库的实现:

void Quaternion_fromEulerZYX(double eulerZYX[3], Quaternion* output)
{
    assert(output != NULL);
    // Based on https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
    double cy = cos(eulerZYX[2] * 0.5);
    double sy = sin(eulerZYX[2] * 0.5);
    double cr = cos(eulerZYX[0] * 0.5);
    double sr = sin(eulerZYX[0] * 0.5);
    double cp = cos(eulerZYX[1] * 0.5);
    double sp = sin(eulerZYX[1] * 0.5);

    output->w = cy * cr * cp + sy * sr * sp;
    output->v[0] = cy * sr * cp - sy * cr * sp;
    output->v[1] = cy * cr * sp + sy * sr * cp;
    output->v[2] = sy * cr * cp - cy * sr * sp;
}

注意最后三个字符串。 x 和 y 在表达式中具有不同的符号。 Qt 函数对应常见的欧拉角矩阵乘法,但不是其他库的实现。

所以,我很困惑。其他图书馆如何运作?因为我使用非 Qt 库得到了错误的结果。

c++ quaternions
1个回答
0
投票

您的 Qt 代码片段使用 Tait-Bryan 角从欧拉角创建四元数。 Tait-Bryan 角是一种特定类型的欧拉角,其中每次旋转都围绕不同的轴 (x, y, z) 发生。

相比之下,其他库可能使用不同的轮换约定。例如,它可能使用 ZYX 欧拉角创建一个四元数,该四元数先绕 z 轴旋转,然后绕 y 轴旋转,最后绕 x 轴旋转。这些约定的差异可能会导致结果出现差异。

要解决此问题,您需要确保在两个库中以相同的顺序和顺序应用轮换。如果其他库使用不同的约定,您需要相应地调整代码以匹配该约定。

以下是如何调整其他库的方法以匹配 Qt 库的约定的示例:

void Quaternion_fromEulerZYX(double eulerZYX[3], Quaternion* output)
{
    assert(output != NULL);
    // Adjusted to match the Qt library's convention
    double cy = cos(eulerZYX[1] * 0.5);  // yaw
    double sy = sin(eulerZYX[1] * 0.5);  // yaw
    double cr = cos(eulerZYX[2] * 0.5);  // roll
    double sr = sin(eulerZYX[2] * 0.5);  // roll
    double cp = cos(eulerZYX[0] * 0.5);  // pitch
    double sp = sin(eulerZYX[0] * 0.5);  // pitch

    output->w = cy * cr * cp + sy * sr * sp;
    output->v[0] = cy * sr * cp - sy * cr * sp;
    output->v[1] = cy * cr * sp + sy * sr * cp;
    output->v[2] = sy * cr * cp - cy * sr * sp;
}

此代码调整操作顺序以匹配 Qt 库的约定,这可能会解决您所看到的差异。但是,在使用任何库之前,您应该始终确保了解其使用的约定,因为不同的库可能有不同的四元数运算约定。

© www.soinside.com 2019 - 2024. All rights reserved.