回答:
Nathan Reedとteodronが公開したように、ベクトルvを単位長の四元数qだけ回転させるためのレシピは次のとおりです。
1)vから純粋な四元数pを作成します。これは単に、4番目の座標0を追加することを意味します。
2)qで事前乗算し、共役q *で事後乗算します。
3)これは、ベクトルに戻すことができる別の純粋な四元数になります。
このベクトルはを回転させたものです。
これは機能していますが、最適とはほど遠い状態です。四元数の乗算は、大量の演算を意味します。このようなさまざまな実装について興味があり、それらがどこから来たのかを見つけることにしました。これが私の発見です。
qを3次元ベクトルuとスカラーsの組み合わせとして記述することもできます。
四元数の乗算の規則により、また単位長の四元数の共役は単純に逆であるため、
ここで詳述するように、スカラー部分(楕円)はゼロになります。興味深いのは、ベクトル部分、つまり回転ベクトルv 'です。いくつかの基本的なベクトルIDを使用して単純化できます。
これは現在、はるかに最適です。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);
}
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)
)が必要です
まず、q ^(-1)は-q / magnitude(q)ではありません。それはq * /(magnitude(q))^ 2です(q *は共役です。実際の成分を除くすべての成分を否定します)。もちろん、すべての四元数が既に正規化されている場合、通常は回転システムにある場合、大きさによる除算を省略することができます。
ベクトルとの乗算については、quatの実成分をゼロに設定し、そのijk成分をベクトルのxyzに設定することにより、ベクトルをクォータニオンに拡張するだけです。次に、クォータニオン乗算を実行してv 'を取得し、ijkコンポーネントを再度抽出します。(v 'の実数部は常にゼロ、プラスまたはマイナスの浮動小数点エラーになるはずです。)
最初の観察:の逆はでq
はなく-q/magnitude(q)
、完全に間違っています。四元数による回転は、これらの4D複素数の等価物がユニタリーノルムを持っていることを意味しているため、その4D空間のS3単位球にあります。クォートがユニタリであるという事実は、その標準がnorm(q)^2=q*conjugate(q)=1
あり、それがクォートの逆数がその共役であることを意味します。
単位四元数がq=(w,x,y,z)
=(cos(t)、sin(t)v)conjugate(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分で。がんばろう!
四元数によってベクトルを変換する別の方法を次に示します。これは、MSがxnaフレームワークで行う方法です。 http://pastebin.com/fAFp6NnN
私はこれを手作業で解決しようとし、次の方程式/方法を思いつきました:
// 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)を使用しましたが、フォローできることを願っています。特に、ベクトルの実際の部分が消滅することを証明すると、大半が正しいと思います。