【问题标题】:GLM conversion from euler angles to quaternion and back does not hold从欧拉角到四元数和反角的 GLM 转换不成立
【发布时间】:2020-02-21 22:56:59
【问题描述】:

我正在尝试将我存储为欧拉角 glm::vec3 的 OpenVR 控制器的方向转换为 glm::fquat 并返回,但我得到了截然不同的结果,并且游戏中的行为是错误的 (很难解释,但是物体的方向在小范围的角度上表现正常,然后在奇怪的轴上翻转)。

这是我的转换代码:

// get `orientation` from OpenVR controller sensor data

const glm::vec3 eulerAnglesInDegrees{orientation[PITCH], orientation[YAW], orientation[ROLL]};
debugPrint(eulerAnglesInDegrees);

const glm::fquat quaternion{glm::radians(eulerAnglesInDegrees)};
const glm::vec3 result{glm::degrees(glm::eulerAngles(quaternion))};
debugPrint(result);

// `result` should represent the same orientation as `eulerAnglesInDegrees`

我希望eulerAnglesInDegreesresult 是相同方向的相同或等效表示,但显然情况并非如此。这些是我打印出来的一些示例值:

39.3851 5.17816 3.29104 
39.3851 5.17816 3.29104 

32.7636 144.849 44.3845 
-147.236 35.1512 -135.616 

39.3851 5.17816 3.29104 
39.3851 5.17816 3.29104 

32.0103 137.415 45.1592 
-147.99 42.5846 -134.841 

正如您在上面看到的,对于某些方向范围,转换是正确的,但对于其他方向范围则完全不同。

我做错了什么?

我查看了现有问题并尝试了一些事情,包括尝试every possible rotation order listed hereconjugating the quaternion 以及其他随机的事情,例如翻转俯仰/偏航/滚动。没有给我预期的结果。

如何使用glm 将欧拉角转换为四元数并返回,表示原始方向?


更多差异示例:

original:      4; 175;   26; 
computed:   -175;   4; -153; 
difference:  179; 171;  179; 

original:     -6; 173;   32; 
computed:    173;   6; -147; 
difference: -179; 167;  179; 

original:      9; 268;  -46; 
computed:   -170; -88;  133; 
difference:  179; 356; -179; 

original:    -27; -73;  266; 
computed:    -27; -73;  -93; 
difference:    0;   0;  359; 

original:    -33; 111;  205; 
computed:    146;  68;   25; 
difference: -179;  43;  180; 

我试图找到一种模式来修复最终的computed 结果,但似乎并不容易识别。


GIF+行为视频:


我的直觉/当前理解的视觉表示:

  • 上图是一个球体,我在中间。当我将枪对准球体的绿色一半时,方向是正确的。当我将枪对准球体的红色一半时,这是不正确的 - 似乎每个轴都反转了,但我不能 100% 确定是这种情况。

【问题讨论】:

  • 遇到欧拉角的云台锁定问题。最好将相机控制作为四元数或受约束的参考框架角度。有些旋转有不止一组欧拉角,180 度旋转有无限的可能性。

标签: c++ quaternions glm-math euler-angles openvr


【解决方案1】:

32.7636 144.849 44.3845 -147.236 35.1512 -135.616

这些都是一样的。左 33 或右 147。你们彼此相差 180。现在向上看 145 - 这是距离地平线 35 的过去,你的背部是拱形的。 现在滚动,让你回到天空。

如果您需要使用 Euler,请尝试将音高保持在 -90 到 +90 之间,并在 -180 到 +180 之间滚动;

if (pitch > 90) {
   pitch -= 90;
   yaw += 180;
   roll += 180;
}
if (roll > 180) {
   roll = 360 - roll;
}

或类似的东西。

【讨论】:

  • 俯仰、偏航、滚动不是欧拉角,而是位置角,它们的应用取决于参考系的类型:P
  • 对,Yaw/Pitch/Roll 就像对象参考系中的 YXZ Euler。无论顺序(和参考)我的建议都是相似的 - 保持角度受限。
【解决方案2】:

表示旋转的任何类型的 3 个角度的定义不仅由旋转的顺序给出,如果它们是外部或外部的,而且在定义每个元素的映射时选择哪个角度间隔3D Rotation Group 到 3 个角度的元组。

不幸的是,软件库通常无法明确提及它们支持的角度子集,因此通常有必要测试它们的行为或直接检查源代码。有关 glm 的相关问题,请参阅https://github.com/g-truc/glm/issues/569,有关我工作的另一个库的相关讨论,请参阅https://github.com/robotology/idyntree/pull/504

在 glm master 中,通过快速检查代码 (https://github.com/g-truc/glm/blob/6543cc9ad1476dd62fbfbe3194fcf19412f0cbc0/glm/gtc/quaternion.inl#L10) 以及在 C++ 中 asin image is roughly (-90.0, 90.0)atan2 image is roughly (-180.0, 180.0) 中,glm 中假定的间隔似乎大致为 (-180.0, 180.0 ) x (-90.0, 90.0) x (-180.0, 180.0),因此通过将 第二个角度(偏航,使用您正在使用的名称)限制为 (-90.0, 90.0)。因此,您在 GLM 级别看到的基本上是从提供的角度到 (-180.0, 180.0) x (-90.0, 90.0) x (-180.0, 180.0) 范围内的等效角度的映射。

然而,这个角度是否相等取决于它们的使用方式,即如果你有一个库钳制使用范围之外的欧拉角,而不是将其转换为等效角度,那么您将获得奇怪的结果。出于这个原因,我认为了解您的问题以了解如何生成这些角度会很有趣(尤其是中间角度似乎是奇怪的范围 (-90, 270) 的一部分,即使选择有效)以及如何解释它们以在可视化中呈现对象。一旦您了解了这一点,即使渲染函数在原始应用范围内的角度工作正常,您也可以编写一个函数来将“原始应用角度”映射到“GLM 角度”及其倒数,您可以将其用于您的原始目的。

【讨论】:

    【解决方案3】:

    大致遵循tonyadvice 并经过反复试验和模式识别,我设法找到了一种在转换后恢复原始值的方法。

    • oxoyoz 是原始 pitchyawroll 度数, 在任何转换之前;

    • fxfyfz 是新的 pitchyawroll 度数,在转换“欧拉->四元数->欧拉”后获得(通过glm::degrees(glm::eulerAngles(glm::normalize(quaternion))))。

    if (oy > 90.f)
    {
        fx -= 180.f;
        fy -= 180.f;
        fy *= -1.f;
        fz += 180.f;
    
        if (ox > 0.f)
        {
            fx += 360.f;
        }
    }
    

    上面的代码似乎使原始角度值和转换后的角度值完全匹配。虽然它回答了最初的问题,但它并没有解决我的实际问题......我正在转换为四元数以便平滑地插值到另一个角度。然而,似乎在转换后的四元数上使用glm::mix - 再次 - 在非常不可预测的旋转中。

    【讨论】:

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