web-dev-qa-db-ja.com

オイラー角から四元数へのGLM変換およびその逆は成り立たない

オイラー角の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 

上記のように、一部の方向範囲では変換は正しく行われますが、他の方向範囲では完全に異なります。

何が悪いのですか?

私は既存の質問を見て、いくつか試してみました ここにリストされているすべての可能な回転順序四元数の共役 、およびピッチ/ヨーの反転などの他のランダムなものを試しました/ロール。期待した結果が得られなかった。

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 +動作のビデオ:

Video excerpt


私の直感/現在の理解の視覚的表現:

Visual diagram

  • 上の写真は球体で、真ん中です。球の緑の半分に向けて銃を向けると、向きは正しいです。球の赤い半分に向けて銃を向けると、それは正しくありません。すべての軸が反転しているように見えますが、100%確実ではありません。
4
Vittorio Romeo

tony の大体 advice に従い、試行錯誤とパターンの識別を行った後、変換後に元の値を復元する方法を見つけました。

  • oxoy、およびozは、元のpitchyaw、およびroll、変換前。

  • fxfyfzは新しいpitchyaw、およびroll度単位で、「オイラー->クォータニオン->オイラー」( 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変換結果の後のクォータニオン-再び-非常に予測できないローテーション。

1
Vittorio Romeo