我正在尝试使用 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/