5

3D 回転を制限する正しい/最良の方法は何ですか (オイラー角やクォータニオンを使用)?

どうやら私のやり方が間違っているようです。アニメーション用に骨格階層のボーンに回転を適用しています。ボーンが間違った方向に「ジャンプ」することがあり、個々のオイラー コンポーネントが範囲の反対側に回り込んでいます。

オイラー角を使用して現在の向きを表し、クォータニオンに変換して回転を行い、各オイラー角軸を個別にクランプします。基本的に私がやっていることを示す C++ 擬似コードは次のとおりです。

Euler min = ...;
Euler max = ...;

Quat rotation = ...;
Euler eCurrent = ...;

// do rotation
Quat qCurrent = eCurrent.toQuat();
qCurrent = qCurrent * rotation;
eCurrent = qCurrent.toEuler();

// constrain
for (unsigned int i = 0; i < 3; i++)
    eCurrent[i] = clamp(eCurrent[i], min[i], max[i]);
4

2 に答える 2

1

オイラー角の問題の 1 つは、同じ回転を表す方法が複数あるため、滑らかな一連の回転を簡単に作成できますが、その回転を表す角度がジャンプする可能性があることです。角度が制約された範囲に出入りすると、説明しているような効果が見られます。

X 回転のみが関係し、X 回転が 0 から 180 度の間に制限されていると想像してください。また、クォータニオンをオイラー角に変換する関数が -180 から 180 度の角度を与えたと想像してください。

次に、この一連の回転があります。

True rotation    After conversion    After constraint
179              179                 179
180              180                 180
181             -179                 0

回転がスムーズに変化しているにもかかわらず、変換関数によって結果が特定の範囲で表現されるように強制されるため、結果が一方から他方に突然ジャンプすることがわかります。

四元数をオイラー角に変換する場合、前の結果に最も近い角度を見つけます。例えば:

eCurrent = closestAngles(qCurrent.toEuler(),eCurrent);
eConstrained = clampAngles(eCurrent,min,max);

次回のために eCurrent 値を記憶し、eConstrained 回転をスケルトンに適用します。

于 2012-05-20T13:49:52.887 に答える
0

ここでの問題は、適用している拘束が、適用される回転と関係がないことです。概念的な観点から、これはあなたが達成しようとしていることです:

  • ボーンが拘束されていない状態にあると仮定します。
  • 回転を適用
  • ボーンが制約を超えていますか? はいの場合は、それ以上拘束されていないところまで回転させます

オイラー回転をクランプするコードは、ボーンを元に戻す部分です。ただし、このコードは元のボーンの回転を無視するため、スナップなどの奇妙な動作が見られます。

これを処理する簡単な方法は、代わりにこれを行うことです。

  • 骨が拘束されていない状態にあると仮定する
  • 回転を適用
  • 骨が制約を超えたかどうかをテストする
  • はいの場合、拘束が動きを止める場所を見つける必要があります。
    1. 回転を半分にして、逆に適用します
    2. ボーンは制約を超えていますか? はいの場合は 1 へ
    3. いいえの場合は、回転を半分にして、正方向に適用します。後藤2
  • 拘束角度の許容範囲内に収まるまで、それを続けます

これでうまくいきますが、回転クォータニオンがすべての角度に適用されているため、他の場所に自由がある場合でも、これらの制約のいずれかが正味になると回転が停止します。

代わりに、互いに独立して回転を適用すると、クランプまたは上記の手法を確実に使用して拘束を尊重し、ターゲットにできるだけ近づけて回転させることができます。- -

于 2012-05-20T05:31:33.200 に答える