14

シーンの説明を含むファイルをロードし、OpenGL を使用して表示するプログラムを作成しています。私はすべての数学演算に GLM を使用しています。シーン ファイル内の回転は、クォータニオン形式で保存されます。私のシーン管理システムはオブジェクトの回転をオイラー角の形式で取得し、これらの角度は後で描画時に回転マトリックスに変換されます。

したがって、ロード プロセスはクォータニオン回転を取得し、それらをオブジェクト クラスに格納するためにオイラー角に変換し、次にこれらのオイラー角を描画用の回転行列に変換します。glm::eulerAngles と glm::eulerAngleYXZ 関数を (それぞれ) 使用して、これら 2 つの操作を実行しています。

ただし、間違った結果が得られます。たとえば、クォータニオン {0.500 -0.500 0.500 0.500} (これは WXYZ) を正しく理解していれば、+Z 軸から +Y 軸への矢印の回転を表す必要があります。しかし、プログラムを実行すると、+X 軸に沿った矢印が表示されます。

四元数の理解に何らかの欠陥があると思いますが、中間のオイラー角形式をスキップすることで、期待どおりの結果を得ることができます。glm::toMat4 を使用してクォータニオンを回転行列に直接変換することで、+Z 矢印が +Y を指す回転が得られます。

どちらの方法も単純で正しいように見えるため、これら 2 つの異なる出力を調整するのに苦労しています。私の質問を簡単にするために、これらの 2 つの一見同等の方法が異なる結果をもたらすのはなぜですか。

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f; // eulerAngleYXZ takes radians but eulerAngles returns degrees
glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);
// transform1 rotates a +Z arrow so that it points at +X

glm::quat q(.5, -.5, .5, .5);
glm::mat4 transform2 = glm::toMat4(q);
// transform2 rotates a +Z arrow so that it points at +Y
4

3 に答える 3

6

あなたはおそらく今までにこれを理解した...しかし

この機能を実行する eulerAngle シーケンスは次のとおりです。

glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;

戻る?'YXZ' シーケンスを明示的に返さない場合、次の関数を適切に使用できません。

glm::mat4 transform1 = glm::eulerAngleYXZ(euler.y, euler.x, euler.z);

変数 'euler' は、回転行列に変換するために指定した関数と同じシーケンス タイプでなければなりません。

ここを見ると、関数「glm::eulerAngles」がピッチ、ヨー、ロールとして「XYZ」を返すように見えます。したがって、それらが「YXZ」、またはヨー、ピッチ、ロールであると仮定すると、正しくありません。

前に述べたように、オイラー角と回転行列では順序が重要です!

于 2012-10-20T19:39:28.807 に答える
4

オイラー角を扱う場合、乗算の順序は重要です。YXZ と XYZ は非常に異なる回転を生成します。

軸ごとに個別の行列を計算し、必要な順序でそれらを掛け合わせることができます。

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q) * 3.14159f / 180.f;

glm::mat4 transformX = glm::eulerAngleX(euler.x);
glm::mat4 transformY = glm::eulerAngleY(euler.y);
glm::mat4 transformZ = glm::eulerAngleZ(euler.z);

glm::mat4 transform1 =
    transformX * transformY * transformZ; // or some other order
于 2012-08-21T12:22:51.703 に答える
2

結果はすでにラジアンだと思います。変換する必要はありません。

glm::quat q(.5, -.5, .5, .5);
glm::vec3 euler = glm::eulerAngles(q); // * 3.14159f / 180.f;

glm::mat4 transformX = glm::eulerAngleX(euler.x);
glm::mat4 transformY = glm::eulerAngleY(euler.y);
glm::mat4 transformZ = glm::eulerAngleZ(euler.z);

glm::mat4 transform1 =
    transformX * transformY * transformZ; // or some other order
于 2020-05-27T07:23:01.620 に答える