クォータニオンの使用:それらで何ができますか?(数学なし)


24

私はゲーム開発者であり、数学を勉強していません。そのため、ツールとしてクォータニオンのみを使用します。また、3D回転を使用するには、クォータニオンを使用する必要があります(またはマトリックスですが、この質問ではクォータニオンに留まりましょう)。多くの開発者がそれらを使用することが重要だと思います。それが私の知識を共有し、できれば私が持っている穴を埋めたい理由です。今…

だから私が理解した限り:

クォータニオンは2つのことを説明できます。

  1. 3Dオブジェクトの現在の向き。
  2. オブジェクトが実行できる回転変換。(rotationChange)

クォータニオンでできること:

乗算:

  1. 四元数endOrientation =四元数rotationChange *四元数currentOrientation;

    たとえば、3Dオブジェクトは左に90°回転します-そして、私の回転は、右に180°回転し、最後に3Dオブジェクトは90°回転します。

  2. クォータニオンrotationChange =クォータニオンendRotation * Quaternion.Inverse(startRotation);

    これにより、rotationChangeを取得し、これを別のOrientationに適用できます。

  3. Vector3 endPostion = Quaternion rotationChange * Vector3 currentPosition;

    たとえば、次のようになります。私の3Dオブジェクトは位置(0,0,0)にあり、乗算する回転は180度右への回転であり、終了位置は(0、-50,0)のようなものです。そのクォータニオンの中には、軸とその軸の周りの回転があります。ポイントをその軸のY度に向けます。

  4. Vector3 rotateOffsetVector = Quaternion rotationChange * Vector3 currentOffsetVector;

    例:開始方向はUP-(0,1,0)を示し、乗算した回転は右に180°回転し、終了方向は下を示しています。(0、-1,0)

ブレンド(LerpとSlerp):

  1. クォータニオンcurrentOrientation = Quaternion.Slerp(startOrientation、endOrientation、interpolator)

    補間器が1の場合:currentOrientation = endOrientation

    補間器が0の場合:currentOrientation = startOrientation

    Slerpはより正確に補間し、Lerpはより多くのパフォーマンスを補間します。

私の質問:

今まで説明したことはすべて正しいですか?

クォータニオンでできるのはそれだけですか?(obv。not)

他に何ができますか?

2つのクォータニオン間のDot製品とCross製品は何に適していますか?

編集:

いくつかの回答を含む質問を更新しました


2つではなく、nさまざまな向き(姿勢、ポーズなど)があるとします。次に、重みを使用してそれらを平均化し、slerp / lerpを効果的に一般化できます。クォータニオンをローターに変換することもできます。これは、剛体に一定時間角速度を適用するのと同じです。したがって、四元数による角速度積分も記述できます。また、異なる2つの方向がどのように異なるかを推定することもできます(超球上の2つの四元数がまたがる弧の長さを計算します)。
テオドロン

そして、はい、一目で、あなたの理論的根拠は正しいです(四元数のあなたの理解は非技術者にとって非常に良いです)。これはコメントには不適切ですが、おめでとうございます!技術的に才能のある人でさえ、すべてのクォータニオンの用途を知っているわけではありませんが、目的のためのソフトウェアエンジニアリングツールとして使用しているだけです。
テオドロン

4
「そして、3D回転で作業できるようにするには、クォータニオンを使用する必要があります」この文がいかに間違っているかを十分に強調することはできません。ゲーム開発にはオイラーまたはテイトブライアンのアングルを使用できますが、唯一の問題はジンバルロックです。ゲーム開発者になりたい場合は、数学が必要になります。学ぶ必要があります。
バリント

1
「ゲーム開発者」と「数学を勉強していない」は矛盾です。
マーガレットブルーム

2
質問に対してあなたがやろうとしていることに感謝しますが、答えは質問ではなく答えの中にあるべきです。照合する価値があると思う場合は、「要約」の回答を作成します。
基本的な

回答:


23

乗算

少なくともUnityのクォータニオンの実装に関しては、質問で説明されている乗算順序は正しくありません。3D回転は可換ではないため、これは重要です。

したがって、オブジェクトをrotationChange開始してオブジェクトを回転させたい場合は、次のようにcurrentOrientation記述します。

Quaternion newOrientation = rotationChange * currentOrientation;

(つまり、変換は左にスタックします-Unityのマトリックス規則と同じです。右端の回転が最初に適用されます/「最もローカルな」端に)

そして、回転によって方向またはオフセットベクトルを変換したい場合は、次のように記述します。

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(逆の場合、Unityはコンパイルエラーを生成します)

ブレンド

ほとんどの場合、Lerpingの回転を回避できます。これは、四元数で「フードの下」で使用される角度が回転角度の半分であるため、マトリックスのようなもの(一般にLerpがうまくいきません!)よりもLerpの線形近似にかなり近くなるためです。詳細については、このビデオの約40分をご覧ください

Slerpが本当に必要な場合の1つは、アニメーションタイムライン上のキーフレーム間の補間のように、一定の速度が必要な場合です。出力が2つの入力の中間にあることだけを気にする場合(アニメーションのレイヤーのブレンドなど)、通常Lerpは非常に役立ちます。

ほかに何か?

2つの単位四元数の内積は、それらの間の角度の余弦を与えるので、回転を比較する必要がある場合、類似性の尺度として内積を使用できます。ただし、これは少しわかりにくいので、読みやすいコードでは、代わりにQuaternion.Angle(a、b)を使用することがよくあります。

Unityがクォータニオンに提供するこれらのタイプの便利なメソッドは、非常に便利です。ほとんどすべてのプロジェクトで、これを少なくとも数回使用しています:

Quaternion.LookRotation(Vector3 forward, Vector3 up)

これにより、以下のクォータニオンが作成されます。

  • forwardベクトル引数に正確に沿って指すようにローカルz +軸を回転します
  • ローカルのy +軸を回転させて、upベクトル引数(指定(0, 1, 0)されている場合)または省略されている場合に可能な限り近づけます

「アップ」が「できるだけ近く」になるのは、システムが過剰に決定されているためです。z +に向かい、forward2つの自由度(ヨーとピッチ)を使用するため、残りの自由度は1つだけです(ロール)。

私は非常に頻繁に、正反対の正確さのプロパティが必要です:ローカルy +がに沿って正確にポイントしup、ローカルz + forwardが残りの自由にできるだけ近くなるようにします。

これは、たとえば、運動入力用のカメラ相対座標フレームを形成しようとするときに発生します。ローカルの上方向を床または傾斜した表面の法線に対して垂直のままにして、入力がキャラクターを地形にトンネルさせないようにしますまたはそれらを浮揚させます。

また、戦車の砲塔ハウジングをターゲットに向け、上下に照準を合わせたときに戦車の本体から剥がれることなくこれを取得することもできます。

これを行うための独自の便利な関数を作成しLookRotationて、重いものを持ち上げることに使用できます。

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp)
{
    Quaternion rotateZToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion rotateYToZ = Quaternion.Euler(90f, 0f, 0f);

    return rotateZToUp * rotateYToZ;
}

ここでは、最初にローカルy +をz +に、ローカルz +をy-に回転します。

次に、新しいz +を上方向に回転させ(その結果、正味の結果はに沿ったローカルy +ポイントになりますexactUp)、新しいy +は負の順方向に可能な限り近くします(したがって、正味の結果は、approximateForward

もう1つの便利な便利な方法はQuaternion.RotateTowards、のようなものです。

Quaternion newRotation = Quaternion.RotateTowards(
                             oldRotation, 
                             targetRotation,
                             maxDegreesPerSecond * Time.deltaTime
                         );

これによりtargetRotation、フレームレートに関係なく、一貫した制御可能な速度で閉じることができます-ゲームプレイの仕組みの結果/公平性に影響する回転にとって重要です(キャラクターの動きを回したり、プレイヤーに砲塔を追跡させるなど)。このような状況で単純にLerping / Slerpingを実行すると、高いフレームレートで動きが激しくなり、ゲームのバランスに影響する場合があります。(これらの方法が間違っていると言うのではなく、公平性を変えずに正しく使用する方法があります。注意が必要です。これRotateTowardsを処理する便利なショートカットを提供します)


ヒント:ビデオURLの最後に&t = 40mを追加して、そこに直接ジャンプします(オプションで、たとえば40m5s)。四元数のドット積は、球体のゲーム世界を扱う場合、または回転する球体の塊を方向付ける場合により広く役立ちます。
ルークブリッグス

@Luke Briggs:球形のゲームの世界のポイントは、あなたがそれに挑戦するなら、(特に図表を使って)独自の答えで詳しく説明する価値があるように思えます。:)
DMGregory

素晴らしいアイデア-ここは午前3時です(だからちょっとちょっぴり出てくると思います!)が、明日何かをまとめることができたらうれしいです(覚えているなら!)
ルークブリッグズ

1
編集:答えを考えて少し夢中になったので、挑戦を受け入れました!P:人々はそれに入った深夜の火傷を知ることができるので、私は、少なくともラフカットとしてそれをマークします
ルーク・ブリッグス

行くぞ!私はあなたの答えが既に基礎となる機能を非常にうまくカバーしていることに基づいて、グラフィカルな概要の意味でそれをカバーしようとしました。寝る時間だと思う!
ルークブリッグス

14

ドット積はどこで使用されますか?

Unityでは、ドット積の最も一般的なユーザーの1人は、==またはで2つの四元数が等しいかどうかを確認するときです!=。Unityは、内部のx、y、z、w値を直接比較するのではなく、ドット積を計算して類似性をチェックします。呼び出しが予想よりも高くなるので、これを覚えておく価値があります。

また、興味深いユースケースでも使用します。

クォータニオンドット積の楽しみ-球面世界と軌道

惑星全体、さらには太陽系全体のシミュレーションがますます一般的になっています。これをリアルタイムで実行するには、クォータニオンドット積も必要です。それらの多く。クォータニオンドット積は非常に使用されていませんが、確かに用途があります。見てみましょう。

まず、考慮する一連の回転があります。

  1. (オプション)銀河中心の周りの星
  2. 星の周りの惑星
  3. 惑星の傾き
  4. 惑星のスピン
  5. 近くのグリッドセルの位置(惑星のコアを中心に回転)*
  6. 複数の軌道面

それらをすべて組み合わせると、非常に複雑になります(そして膨大な数になります!)。視聴者が惑星の表面に立っているとき、ゲームワールド空間を狂った速度で急ぐことは望ましくありません。実際には、それらは静止しており、原点の近くにあります-代わりにプレイヤーの周りで宇宙を動かしてください

回転する惑星

重要なことは、このシナリオで惑星のスピンとチルトを正しくできるようにするために、ポールを軸ロックして、上の画像でのみ上下にスイングできるようにする必要があります(つまり、プレイヤーが移動すると「上に」スイングする)北)。そこに四元数の内積が入ります。ここで内積を使用せずに、単に傾斜を掛けただけの場合、これは起こります。

誤って傾けられた「惑星」

周回する「惑星」の極が常に星に向かって傾いていることに注目してください。これは現実に起こることではありません-傾きは固定方向です。

話題からあまり離れることなく、ここに簡単な要約を示します。

  • 球体では、方向も表面の位置をきちんと表します。
  • たくさんの回転を組み合わせて組み合わせることができます。
  • すべてを回転として説明します。視聴者の位置も。これにより、最終的には操作が少なくなり、パフォーマンスが向上します。
  • 回転間の角度(ドット積)は、経度の測定に役立ち、傾斜の処理に特に役立ちます。

角度のみを取得することにより、その不要な回転の一部ドロップします。同時に、経度の測定も行いました。これは、地域の気候だけでなく、航海にも役立ちます。

*惑星は多くのグリッドセルから構成されています。近くのものだけが実際に表示されます。


2
これはシーンの設定と問題の動機付けに非常に役立ちますが、四元数の内積の計算方法(つまり、連鎖に使用するdot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w四元数合成とは対照的なスカラー積)についてはまだ少し曖昧です回転)この問題を解決するのに役立ちます。これについてもう少し詳しく説明できるなら、喜んで賛成します(私はあなたの強打からあなたを守るつもりはありません...私は睡眠を意味します!)
DMGregory

@DmGregory簡単に言うと、傾きは傾きです。その1つを除いてすべてがうまく構成されます(そうでなければ、惑星はその星の周りをぐらつくように見えるでしょう)。明日はコンテキストを追加します(できれば!)。
ルークブリッグス

@DMGregoryいくつかの追加情報を追加しました(眠れませんでした!)-うまくいけば、それがより明確になります。
ルークブリッグス

1
少し密度が高ければ申し訳ありませんが、何度か読み直した後、式でドット積を使用して、説明している変換を達成する方法がわかりません。実行する操作を明示的にレイアウトする小さな擬似コードを追加できますか?
DMGregory

@DMGregory私は四元数に精通していませんが、これが球体上の回転である場合、これは回転合成ではありません。これは、球体ジオメトリとベクトルを使用して、任意の円周の球体の表面上の「線」の法線ベクトルを計算しています。繰り返しになりますが、答えはほとんど意味がありませんし、この質問も意味がありませんが、球面ジオメトリを使用していると思います。
グレートダック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.