我注意到 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 库得到了错误的结果。
您的 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 库的约定,这可能会解决您所看到的差异。但是,在使用任何库之前,您应该始终确保了解其使用的约定,因为不同的库可能有不同的四元数运算约定。