将四元数转换为欧拉角.Y 角范围的问题
Converting quaternions to Euler angles. Problems with the range of Y angle
我正在尝试使用 Irrlicht 作为图形引擎和物理 ODE 来编写 C++ 年的 3D 模拟。然后我使用一个函数将常微分方程四元数转换为伊利希特欧拉角。为了做到这一点,我正在使用这段代码。
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
范围内旋转node->getRotation().Y
.
拉角(任何类型的)都有一个奇点。对于您正在使用的那些特定的欧拉角(看起来像泰特-布莱恩角或其某些变体),奇点是正负 90 度俯仰 (Y)。这是欧拉角的固有限制,也是它们很少在任何严肃环境中使用的主要原因之一(飞机动力学除外,因为所有飞机俯仰速度矢量的能力都非常有限(可能不是水平的),因此它们很少接近该奇点)。
这也意味着您的计算实际上只是两个等效解决方案之一。对于给定的四元数,欧拉角有两种表示相同旋转的解决方案,一种在奇点的一侧,另一种反映第一个。由于这两种解决方案都是等效的,因此您只需选择最简单的一种,即间距在 -90 到 90 度之间。
此外,您的代码需要处理接近奇点以避免获得 NaN。换句话说,您必须检查是否接近奇异点(俯仰上的 -90 度和 90 度),如果是,请使用替代公式(只能计算一个最接近旋转的角度)。
如果有什么方法可以完全避免使用欧拉角,我强烈建议你这样做,几乎任何旋转的表示都比欧拉角更可取。Irrlicht 原生使用矩阵,还支持通过轴角表示设置/获取旋转,这更好用(并且更容易从四元数获得,并且没有奇点)。
想想地球的地球。它上面的每个点只能定义纬度(在[-90, 90]
范围内)和经度(在[-180, 180]
范围内)。因此,可以使用这些角度指定球体上的每个点。现在,球体上的点指定一个向量,球体上的所有点指定所有可能的向量。因此,就像本文中指出的那样,您使用的公式将生成所有可能的方向。
希望这有帮助。
- 示例代码中使用分隔符将 std::string 拆分为 std::vector 的范围问题
- 命名空间范围问题
- 断言失败错误,C++中的矢量下标超出范围问题
- 指针范围问题和返回类中封装的指针向量内的指针引用
- PlatformIO 的范围问题(?)
- 无法编译 - 范围问题
- 需要帮助将矢量解决范围问题.C
- 来自 gmock 的默认值的范围问题
- 可能的继承范围问题:
- #pragma警告(disable:XXXX)的行为与预期不符(范围问题)
- OpenGL的范围问题
- C++ 引用变量范围问题
- 内存引用范围问题:变量值被重置,如何将值分配给LPCWSTR
- 矢量范围问题
- sed/regex - 更新具有范围问题的源文件
- C++类和范围问题
- C++ 程序未正确执行,可能是范围问题
- 类范围问题的向量
- 如何创建一个通用指针,它可以处理int和double变量并避免范围问题
- 命名空间别名范围问题