4

我正在尝试将我存储为glm::vec3欧拉角的 OpenVR 控制器的方向转换为 aglm::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`

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

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 

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

我究竟做错了什么?

我查看了现有的问题并尝试了一些事情,包括尝试此处列出的所有可能的旋转顺序共轭四元数以及其他随机的事情,例如翻转俯仰/偏航/滚动。没有给我预期的结果。

如何将欧拉角转换为四元数并返回,表示原始方向,使用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% 肯定是这种情况。
4

3 回答 3

4

32.7636 144.849 44.3845 -147.236 35.1512 -135.616

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

如果需要使用欧拉,尽量保持pitch在-90到+90,roll在-180到+180;

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

或类似的东西。

于 2020-02-22T03:11:17.093 回答
2

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

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

在 glmmaster中,通过快速检查代码(https://github.com/g-truc/glm/blob/6543cc9ad1476dd62fbfbe3194fcf19412f0cbc0/glm/gtc/quaternion.inl#L10)以及在 C++ 中asin图像大致为( -90.0, 90.0)并且atan2图像大致为 (-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 角度”及其倒数,您可以将其用于您的原始目的。

于 2020-02-22T09:56:04.753 回答
1

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

  • oxoyoz是在任何转换之前的原始俯仰偏航滚动度数;

  • fxfyfz是新的pitchyawroll度数,在转换“Euler -> quaternion -> Euler”(通过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在转换后使用四元数 - 再次 - 在非常不可预测的旋转中。

于 2020-02-24T14:11:50.887 回答