2013-01-21 63 views
1

我正在尝试使用Irrlicht作为图形引擎和物理ODE在C++中编写3D模拟。然后我使用函数将ODE四元数转换为Irrlicht euler角。为了做到这一点,我使用这个代码。将四元数转换为欧拉角。 Y角度范围的问题

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度范围内。至少我需要得到一个旋转的0..360的范围内,当我打电话节点 - > getRotation()。Ÿ

任何一个可以帮我这个好吗?

+2

在'[0°,360°]','sin'取的每个值的两倍,因此存在用于'asin'(反正弦函数)没有合理的方式为0°和360°之间返回值。 – us2012

回答

6

欧拉角(任何类型)有一个奇点。在你使用的那些特定的欧拉角(看起来像泰特 - 布赖恩角或其一些变化)的情况下,奇点在正负90度的节距(Y)上。这是欧拉角的固有限制,也是它们在任何严肃背景下都很少使用的主要原因之一(除了飞机动力学因为所有飞机的速度矢量(可能不是水平的)都有非常有限的俯仰能力,所以他们很少来到这个奇点附近)。

这也意味着,你的计算实际上只是两个等价的解决方案之一。对于一个给定的四元数,欧拉角有两种解决方案,代表相同的旋转,一个在奇点的一边,另一个与第一个相反。由于这两种解决方案都是相同的,所以您只需从最容易的一面选择一个,即音调在-90到90度之间。

此外,你的代码需要处理,以避免得到NaN的接近奇点。换句话说,您必须检查您是否接近(具有小容差)奇点(音高-90和90度),如果是,则使用替代公式(它只能计算一个最接近的角度旋转)。

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

1

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

希望这会有所帮助。