ワールドスペースにオブジェクトがあります。たとえば、(0,0,0)にあり、それを(10,10,10)に向けて回転させたいとします。
クォータニオンを使用してこれを行うにはどうすればよいですか?
ワールドスペースにオブジェクトがあります。たとえば、(0,0,0)にあり、それを(10,10,10)に向けて回転させたいとします。
クォータニオンを使用してこれを行うにはどうすればよいですか?
この質問はまったく意味がありません。オブジェクトが特定のポイントに「向き合う」ようにしたいと言いましたが、それでは十分な情報が得られません。
まず、その方向を向いているとはどういう意味ですか?OpenGLでは、ローカル参照フレームの-z軸が、外部参照フレームの指定された方向に位置合わせされていることを意味します。この位置合わせを行うには、オブジェクトの関連する軸が現在「向いている」方向を知る必要があります。
ただし、それでも一意の変換を定義することはできません。-z軸をポイントにする方向がわかっている場合でも、オブジェクトはその軸を中心に自由に回転します。このため、関数では「at」方向と「up」方向gluLookAt()
を指定する必要があります。
次に知っておく必要があるのは、最終結果をどのような形式にする必要があるかということです。オブジェクトの方向は、多くの場合、クォータニオン形式で保存されます。ただし、オブジェクトをグラフィカルに回転させたい場合は、回転行列が必要になる場合があります。
それでは、いくつかの仮定を立てましょう。オブジェクトがワールドのポイントcの中心にあり、デフォルトの配置になっていると仮定します。つまり、オブジェクトのx、y、およびz軸は、ワールドのx、y、およびz軸と位置合わせされます。これは、世界に対するオブジェクトの方向を、単位行列または単位元数として表すことができることを意味します( w[1 0 0 0]
が最初に来る四元数の規則を使用)。
オブジェクトの-z軸を点p := [px py pz]に揃える最短の回転が必要な場合は、軸aを中心にφだけ回転します。次に、これらの値を見つけます。最初に、ベクトルpcを正規化し、次に単位長-zベクトルとの外積を取り、次に再度正規化することにより、軸aを見つけます。
a = normalize(crossProduct(-z、normalize(pc)));
内積の逆コサインを取ることによって検出された、これら2つの単位ベクトル間の最短角度:
φ=acos(dotProduct(-z、normalize(pc)));
残念ながら、これは2つのベクトルによって形成される角度の絶対値の尺度です。を中心に回転するときに、それが正か負かを把握する必要があります。よりエレガントな方法があるはずですが、最初に頭に浮かぶ方法は、aと-zの両方に垂直な3番目の軸を見つけて、その内積からターゲット軸で符号を取得することです。Vis:
b = crossProduct(a、-z);
if(dotProduct(b、normalize(pc))<0)φ=-φ;
軸と角度が決まったら、それをクォータニオンに変えるのは簡単です。
q = [cos(φ/ 2)sin(φ/ 2)a ];
この新しいクォータニオンは、オブジェクトの新しい方向を表します。レンダリングの目的でマトリックスに変換することも、必要に応じて、クォータニオン乗算のルールを使用してオブジェクトの頂点を直接回転させることもできます。
2つのベクトル間の回転を表すクォータニオンを計算する例は、Ogre::Vector3クラスのOGREソースコードにあります。
あなたの説明に応えて、そしてこれに答えるために、私は恥知らずに、ここからこれまで見たことがないように見える2つのベクトル間のクアットを見つけるための非常に興味深くてきちんとしたアルゴリズムをコピーしました。数学的には有効なようです。あなたの質問はその背後にある数学に関するものなので、この擬似コードをC++に変換できると確信しています。
quaternion q;
vector3 c = cross(v1,v2);
q.v = c;
if ( vectors are known to be unit length ) {
q.w = 1 + dot(v1,v2);
} else {
q.w = sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2);
}
q.normalize();
return q;
その擬似コードのビットを明確にするために助けが必要な場合は私に知らせてください。ただし、簡単なはずです。
dot(a,b) = a1*b1 + a2*b2 + ... + an*bn
と
cross(a,b) = well, the cross product. it's annoying to type out and
can be found anywhere.
SLERP(球面線形補間)を使用することをお勧めします。C ++でそれを行う方法については、この記事を参照してください。