c++ - 将四元数转换为欧拉角。 Y角度范围问题

标签 c++ math 3d irrlicht ode-library

我正在尝试使用 Irrlicht 作为图形引擎和 ODE 用于物理,用 C++ 编写 3d 模拟。然后我使用一个函数将 ODE 四元数转换为 Irrlicht Euler 角。为了做到这一点,我正在使用这段代码。

void QuaternionToEuler(const dQuaternion quaternion, vector3df &euler)
{
    dReal w,x,y,z;

    w = quaternion[0];
    x = quaternion[1];
    y = quaternion[2];
    z = quaternion[3];

    double sqw = w*w;    
    double sqx = x*x;    
    double sqy = y*y;    
    double sqz = z*z; 

    euler.Z = (irr::f32) (atan2(2.0 * (x*y + z*w),(sqx - sqy - sqz + sqw)) * (180.0f/irr::core::PI));
    euler.X = (irr::f32) (atan2(2.0 * (y*z + x*w),(-sqx - sqy + sqz + sqw)) * (180.0f/irr::core::PI));          
    euler.Y = (irr::f32) (asin(-2.0 * (x*z - y*w)) * (180.0f/irr::core::PI));

}

它可以很好地绘制正确的位置和旋转,但问题来自 asin 指令。它只返回 0..90 - 0..-90 范围内的值,我需要从 0..360 获取范围> 学位。至少我需要在调用 node->getRotation().Y 时在 0..360 范围内旋转。

最佳答案

(任何类型的)欧拉角都有一个奇点。在您使用的那些特定欧拉角的情况下(看起来像 Tait-Bryan 角,或其某些变体),奇点位于正负 90 度俯仰角 (Y)。这是欧拉角的固有局限性,也是欧拉角很少在任何严肃的环境中使用的主要原因之一(除了飞机动力学,因为所有飞机的俯仰能力都非常有限。它们的速度 vector (可能不是水平的),所以它们很少会靠近那个奇点)。

这也意味着您的计算实际上只是两个等价解决方案之一。对于给定的四元数,欧拉角有两个表示相同旋转的解,一个在奇点的一侧,另一个在奇点的一侧镜像。由于这两种解决方案是等价的,您只需选择最简单的一侧,即倾斜度介于 -90 和 90 度之间的一侧。

此外,您的代码需要处理接近奇点的问题,以避免出现 NaN。换句话说,您必须检查您是否接近(具有小公差)奇异点(-90 度和 90 度俯仰),如果是这样,请使用替代公式(它只能计算一个最接近的角度旋转)。

如果有任何方法可以让您完全避免使用欧拉角,我强烈建议您这样做,几乎任何旋转表示都比欧拉角更可取。 Irrlicht native 使用矩阵,还支持通过 axis-angle representation 设置/获取旋转,这更好用(并且更容易从四元数中获得,并且没有奇点)。

关于c++ - 将四元数转换为欧拉角。 Y角度范围问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14447338/

相关文章:

c++ - 仿射旋转矩阵

ios - 将世界坐标转换为对象坐标

java - 图形绘制到窗口后的 "secret"是什么?

c++ - 在 OpenGL 中投影纹理

c++ - 重载取消引用运算符

C++ - 从类内部包含 typedef 结构

c++ - 在 Eclipse Indigo 上构建 C++ 程序时出错

c++ - 使用 Kinect SDK 和 C++ 的 Kinect 音频

c# - C# 中的 GF(256) 有限域乘法函数

C传递3D数组的2D子集