クォータニオンによるvector3の回転


25

私は、指定されたクォータニオンでvector3を回転させようとしています。

私はこれが真実であることを知っています

v=qvq1

私はがちょうどである逆であることを知っていますが、ベクトルを得るためにベクトルの乗算をクォータニオンにマッピングするにはどうすればよいですか?q1qmagntあなたはdeq

を行列として扱い、とを行列に変換してから、を行列からベクトルに変換できることを発見しましたが、これはベクトルを取得するためだけに少し上に見えます。使用できるクリーンな実装はありますか?vqqv

回答:


36

Nathan Reedとteodronが公開したように、ベクトルvを単位長の四元数qだけ回転させるためのレシピは次のとおりです。

1)vから純粋な四元数pを作成します。これは単に、4番目の座標0を追加することを意味します。

p=vバツvyvz0p=v0

2)qで事前乗算し、共役q *で事後乗算します

p=q×p×q

3)これは、ベクトルに戻すことができる別の純粋な四元数になります。

v=(px,py,pz)

このベクトルはを回転させたものです。vvq


これは機能していますが、最適とはほど遠い状態です。四元数の乗算は、大量の演算を意味します。このようなさまざまな実装について興味があり、それらがどこから来たのかを見つけることにしました。これが私の発見です。

qを3次元ベクトルuとスカラーsの組み合わせとして記述することもできます。

q=(ux,uy,uz,s)q=(u,s)

四元数の乗算の規則により、また単位長の四元数の共役は単純に逆であるため、

p=qpq=あなたはsv0あなたはs=sv+あなたは×vあなたはvあなたはs=あなたはvあなたは+ssv+あなたは× v+sv+あなたは×v×あなたは=あなたはvあなたは+s2v+sあなたは×v+sv×あなたは+あなたは×v×あなたは

ここで詳述するように、スカラー部分(楕円)はゼロになります。興味深いのは、ベクトル部分、つまり回転ベクトルv 'です。いくつかの基本的なベクトルIDを使用し単純化できます。

v=あなたはvあなたは+s2v+sあなたは×v+sあなたは×v+あなたは×あなたは×v=あなたはvあなたは+s2v+2sあなたは×v+あなたはvあなたはあなたはあなたはv=2あなたはvあなたは+s2あなたはあなたはv+2sあなたは×v

これは現在、はるかに最適です。2つのドット積、クロス積、およびいくつかの追加:約半分のオペレーション。これは、ソースコードでそのようなものを与えます(一般的なベクトル数学ライブラリを想定):

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}

より良い書面による回答に嫌気がさします。また、ほとんどのパフォーマンスフリークは、組み込み関数を使用してベクトル演算を実行する傾向があることを考慮すると、(特にインテルアーキテクチャでの単純な四元数の乗算でも)かなり高速化されます。
テオドロン

最終結果は、ロドリゲスの回転式に似ています-とにかく同じ基底ベクトルを持ちます。係数が一致するかどうかを確認するには、いくつかのトリガーIDを掘り下げる必要があります。
ネイサンリード

@NathanReedこれは、同じ結果を得る別の方法のようです。これが一致するかどうかも知りたいです。それを指摘してくれてありがとう!
ローランクーヴィドゥー

1
私はGLMのこれの実装をチェックしていましたが、次のように少し異なるように実装されているようです:vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fこれは同様の最適化ですか?多少似ていますが、同じではありません-クロス積のみを使用し、ドット積は使用しません。元のソースコードは、公式のGLMリポジトリのtype_quat.inlファイルにあります。このファイルoperator*は、クォータニオンとベクトル(vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))が必要です
j00hi

7

まず、q ^(-1)は-q / magnitude(q)ではありません。それはq * /(magnitude(q))^ 2です(q *は共役です。実際の成分を除くすべての成分を否定します)。もちろん、すべての四元数が既に正規化されている場合、通常は回転システムにある場合、大きさによる除算を省略することができます。

ベクトルとの乗算については、quatの実成分をゼロに設定し、そのijk成分をベクトルのxyzに設定することにより、ベクトルをクォータニオンに拡張するだけです。次に、クォータニオン乗算を実行してv 'を取得し、ijkコンポーネントを再度抽出します。(v 'の実数部は常にゼロ、プラスまたはマイナスの浮動小数点エラーになるはずです。)


5

最初の観察:の逆はでqはなく-q/magnitude(q)、完全に間違っています。四元数による回転は、これらの4D複素数の等価物がユニタリーノルムを持っていることを意味しているため、その4D空間のS3単位球にあります。クォートがユニタリであるという事実は、その標準がnorm(q)^2=q*conjugate(q)=1あり、それがクォートの逆数がその共役であることを意味します。

単位四元数がq=(w,x,y,z)=(cos(t)、sin(t)vconjugate(q)=(w,-x,-y,-z)と記述されている場合、その共役は=(cos(t)、-sin(t)v)です。ここで、tは回転角の半分で、v回転軸です(もちろん、単位ベクトルとして)。

そのハミルトンの男がより高い次元で複素数の等価物をいじることを決めたとき、彼はまたいくつかの素晴らしい特性につまずきました。たとえば、完全に純粋な四元数q=(0,x,y,z)(スカラーパーツwなし)を使用する場合、そのがらくたをベクトルと見なすことができます(実際には、人々がS2球であるS3球の赤道と呼ぶものの量です! !-19世紀の人々が技術的にどのように障害を受けているかを考えると、今のようにアイフォンカウボーイのように思えます。そのため、ハミルトンはそのベクトルをquat形式で取りv=(0,x,y,z)、quatsの幾何学的特性を考慮した一連の実験を行いました。

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

どこで

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

観察:q *(0、v)* conj(q)は、(0、v ')形式の別のクォートでなければなりません。どうやらこれが起こる理由の複雑な説明はすべて行いませんが、この方法で純粋な想像上の四元数(または、この場合はベクトル)を回転させる場合、同様の種類のオブジェクトを取得する必要があります:純粋な想像上のquatです。 。そして、あなたはあなたの結果としてその想像上の部分を取ります。そこには、四元数のナット(ty)シェルの回転の素晴らしい世界があります。

:使いすぎたフレーズに飛び込む人には、クワットは良いでしょう。ジンバルロックを避けるためです。最初に想像力を解き放つべきです!! クォートは単なる「エレガントな」数学的装置であり、他のアプローチを使用することで完全に回避することができます。完全に幾何学的に等価なものは、軸角度アプローチです。

CODE私が空想するC ++ライブラリはかなり単純ですが、3Dグラフィックの実験者が学習するのに15分以上を無駄にすることなく必要なすべての行列、ベクトル、およびクォート演算があります。 C ++初心者でない場合は15分で。がんばろう!


メモの+1。ほとんどの人は、実際のジンバルロックを達成できなかったに違いないと思います。これは、回転を実行するときの予期しない動作のキャッチフレーズになりました。
スティーブH

ほとんどの人は、適切なジンバルメカニズムを構築できず、3つの回転マトリックスを連結すると、自動的に「オイラー角」表現になると考えられます。インバースキネマティクスを実行しようとするときに冗長性が発生する可能性があるジョイント(実際に必要な方向を生成するのに必要な自由度よりも高い自由度を持っています)。まあ、それはまた別の話題だが、私は、この「伝説の」問題はCGプログラマの間で生成された誇大広告から離れて滞在することのniceを...と思った
teodron

Nitpickery:両方の表現がSO(3)のすべての回転を一意に表すことができるという点で軸角度は同等ですが(大丈夫、通常の二重カバーをモジュロ)、もちろんそれらの間でほぼ自明な変換が前後にありますが、四元数は他のすべての非マトリックス表現よりも作成がはるかに簡単であるという利点。
スティーブンスタドニッキー

特に演算子のオーバーロードを使用する場合、オブジェクト指向プログラミング言語での優れた動作により、構成が簡単になるという利点があります。確かではありませんが、おそらくそれらの球面補間プロパティでさえ、軸角度を保持します(SQUADを除くか?!)。
テオドロン


-1

私はこれを手作業で解決しようとし、次の方程式/方法を思いつきました:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

誰かが私がhttp://pastebin.com/8QHQqGbvを使ったmt派生を見てくれたら感謝します。横スクロールをサポートするテキストエディタにコピーすることをお勧めします

私の記法では、共役ではなく、逆ではなく、異なる識別子を意味するためにq ^(-1)を使用しましたが、フォローできることを願っています。特に、ベクトルの実際の部分が消滅することを証明すると、大半が正しいと思います。

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