【问题标题】:Converting quaternions to Euler angles. Problems with the range of Y angle将四元数转换为欧拉角。 Y角范围问题
【发布时间】:2013-01-05 00:30:32
【问题描述】:

我正在尝试使用 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 范围内进行轮换。

【问题讨论】:

  • 在[0°,360°] 上,sin 对每个值取两次,因此asin(反正弦函数)没有明智的方法返回 0° 到 360° 之间的值。

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


【解决方案1】:

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

这也意味着您的计算实际上只是两个等效解决方案之一。对于给定的四元数,欧拉角有两种表示相同旋转的解,一种在奇点的一侧,另一种反映第一个。由于这两种解决方案是等效的,因此您只需选择最简单的一侧,即俯仰角在 -90 到 90 度之间的那个。

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

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

【讨论】:

    【解决方案2】:

    想想地球。其上的每个点只能使用纬度(在[-90, 90] 范围内)和经度(在[-180, 180] 范围内)定义。因此,可以使用这些角度来指定球体上的每个点。现在球体上的一个点指定一个向量,球体上的所有点指定所有可能的向量。所以就像this article 中指出的那样,您使用的公式将生成所有可能的方向。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-21
      • 2012-08-16
      • 1970-01-01
      • 2019-10-27
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多