Slerping回転ミラー


9

次のコードを使用して、ターゲットを監視するためにゲームキャラクターを回転させます。

        transform.rotation = Quaternion.Slerp(startQuaternion, lookQuaternion, turningNormalizer*turningSpeed/10f)

startQuaternionは、新しいターゲットが指定されたときのキャラクターの現在の回転です。

lookQuaternionは、キャラクターが見るべき方向であり、次のように設定されています。

    destinationVector = currentWaypoint.transform.position - transform.position;
    lookQuaternion = Quaternion.LookRotation(destinationVector, Vector3.up);

turnNormalizerはTime.deltaTimeインクリメントされるだけturningSpeedで、エディターで指定される静的な値です。

問題は、ほとんどの場合、キャラクターが正常に回転する一方で、180度に近づかなければならないときに問題が発生することです。次に、時々それがジッターして回転をミラーリングします:

ここに画像の説明を入力してください

この不十分に描かれた画像では、キャラクター(右側)が左側の円に向かって回転し始めます。左または右に回転するだけでなく、この「ミラーダンス」が開始されます。

  1. 新しいフェーシングに向かって回転し始めます
  2. その後、突然同じ角度にスナップしますが、反対側で回転し続けます

ターゲットを見るまで、この「ミラーリング」を長時間実行します。これは、四元数、slerping / lerpingなどの問題ですか?

EDIT1: どうやら、問題は回転自体から発生するのではありません。より可能性の高い問題は、キャラクターが回転しているときに面に向かって移動することです。キャラクターが動くことを許可されているとき、向きとターゲットの間の角度を制限することで、ジッター/ミラーリング回転が減少し、時には解消されます。

もちろん、これはさらに多くの疑問を投げかけますが、なぜ問題なくキャラクターが同時に移動および回転できないのですか?運動に使用されるコード:

transform.Translate(Vector3.forward * runningSpeed/10f * Time.deltaTime);

「lookQuaternion」はフレームごとに更新されますか?もしそうなら、私の推測は、いくつかの小さな不正確さがプレーヤーがルックローテーションを「オーバーシュート」する一種のジッターを引き起こしているので、新しい方向が「真後ろ」の反対側にあるということです... 。
スティーブンStadnicki

回答:


5

3D空間の各方向は、2つの異なる単位四元数、qおよび-q(コンポーネントごとに否定されたq)で表すことができます。たとえば、3x3の単位行列で表される向きIは、2つの四元数で表すことができます。

 q:  { 0,  0,  0},  1
-q:  {-0, -0, -0}, -1

どちらも3D空間で同じ方向を表し、それらの内積はであり-1、それぞれが他の半球にあり、超球の反対側にあります。

slerpが回転するのに長い弧をとるときに観察する結果は、同じ半球にない2つの四元数の間でSlerpingするときです。それが起こる場合、それらをslerpingする前にそれらの1つを否定するだけで、slerpはより短い弧をとります。

ドット積は、それが発生するかどうかを調べる簡単なツールです。両方の四元数の内積がより小さい場合0、それらは同じ半球にありません。したがって、両方のドット積がより小さい場合0は、他のクォータニオンを打ち消す前に、コンポーネント単位で否定します。


これで試してみて正しく理解できたのかと思い if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Inverse(startQuaternion); }ますが、問題は解決しませんでした。形式がおかしいので申し訳ありません。このコメントセクションを管理することはできません。
Esa

ほとんどではありませんがInverse、これはとは異なる操作ですNegateif(Quaternion.Dot (lookQuaternion, q) < 0) { q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w; }私はC#を使用していませんが、ドキュメントの外観から、Negate-Functionを直接使用することもできるようです。
Maik Semder 2013年

if(Quaternion.Dot (lookQuaternion, startQuaternion) < 0) { startQuaternion = Quaternion.Negate(startQuaternion); }
Maik Semder 2013年

これらは問題を解決しなかったと思います。質問を更新しました。
Esa 2013年

うんそれはおそらく異なるバグの混合です。テスト設定を簡素化し、一度に1つずつテストします。平行移動と回転を同時にテストしません。最初に、一方が機能し、次にもう一方が機能することを確認してから、両方を一緒に機能させます。最初に回転のみに焦点を合わせ、170度から開始してゼロに移動するなど、よく知られている方向の値を使用し、どこが間違っているかを確認して、ここに投稿します
Maik Semder

1

さてあなたの問題は、四元数を形成するこれらの2つのベクトルが180度をなすためです。そのため、どの弧をとるべきかを補間するときに尋ねるべき質問は何ですか。上の弧か下の弧か?

これが基本的にミラーリングを引き起こしているものであり、補間するたびに、角度を維持しながら逆方向に進みます。

このリンクによると。

thetaが180度の場合、回転する最短の方向がないため、結果は未定義です。この状況はまだ正しく処理されていないと思います。qaまたはqbに垂直な任意の軸を選択した方がよいでしょう。これを行うための最良の方法についてのアイデアを感謝します。

必要なのは、開始クォータニオンを中間クォータニオンで補間し(どのアークを取るかを決定するため)、到達したら中間クォータニオンを使用して実際のターゲットクォータニオンに進みます。


1

あなたが見ていると思う問題はコードとは関係ありませんが、球の表面に沿った補間に関する基本的な問題です(この場合、viewDirectionの場合)。球体上の(ほぼ)任意の2つの点の間には、1つの大円があります。たとえば、「開始」点を北極に任意に固定すると、大円は終点が存在する子午線になります。ある点から別の点への補間は、この大きな円に沿って移動します。

現在、球体上のほとんどの点について、近くの点は近くの大円に対応しています。たとえば、ロサンゼルスとフェニックスが横たわっている子午線は、かなり近くにあります。先のポイントがあるときにでも、対掌体開始点の北極に南極- -原点がそこにもはやそれらの両方を通じて、単一の大円ませんが、代わりにすべての他通じ一度経由大円。さらに悪いことに、これは南極近くのポイントが「ほとんどのポイント」ではないことを意味します。2つの点が互いに近く、両方とも南極の近くにあると、子午線が大きく分岐することがあります。

あなたが見ているのは、子午線におけるこの不安定性の現れである、つまり、内挿弧であると思います。ルックターゲットがキャラクターの真後ろにある場合、キャラクターの位置の「オイラー統合」における1次の不正確さや、フレームからフレームへのルック方向を変更する方法は、これらに大きく影響します。 1つのフレームから次のフレームへの異なる補間アーク、これはおそらくあなたが見ている「ずれ」につながるでしょう。

それをどうするかに関する限り、思い浮かぶ最良のことは、フレームごとに「ターゲット」のルック方向を再計算しないことです。代わりに、いくつかのフレームのスパンに同じものを使用し、新しいものを計算して、それをいくつかのフレームに使用します。必要に応じて、いくつかのフレームのスパンにわたって1つのターゲットから次のターゲットに補間することもできます。動きの方向が急激に変化しない。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.