- クオータニオンを使ってボーンを回転させる -
今回はボーンの動かし方を考えてみたいと思います。


・制御をクォータニオンで
このボーンを描いたときに使ったクォータニオンをQとします。
このQに、ボーンをある軸で回転させるクォータニオンqを合成すればよいわけです。
軸となるベクトルは、各座標系のクォータニオンを使って変換すれば求められます。

次の図は前回出てきた図です。

赤い座標系から緑の座標系に変換するクォータニオンをQgとします。
今、赤い座標系をクォータニオンQrを使って回転させたとします。
この回転のときに、緑の座標系・青の座標系が赤い座標系の回転とともに回転しないと、
ボーンがちぎれてしまい、腕のような動きになりません。

そこで、QgとQrを合成します。
この合成によって、緑の座標系にも赤い座標系の回転が加えられることになります。
同じように青のボーンのクォータニオンにもQrを合成すれば赤のボーンの回転と一緒についてきます。
#合成については前回を参照してください。


・実際に動かす
前回のサンプルソースを使ってボーンを動かしてみます。

[実行したところ]



前回描画したボーンを曲げてみたところです。
赤→緑→青の順に親子関係が成り立っていて、
青のボーンには子が無く、赤のボーンの親座標系というのはOpenGLの空間を表す座標系です。


・サンプルソース
前回のサンプルでデータを作成してあるものとします。


Vector drawBone;
drawBone = b[0].position; //最初に描画するボーン位置を入れておく
Quaternion quat; //上位ボーンの回転クォータニオンから下位ボーンの回転クォータニオンを合成したもの

//単位クォータニオンで初期化
quat.t = 1.0;
quat.x = 0.0;
quat.y = 0.0;
quat.z = 0.0;

for(i = 0; i < 3; i++)
{
glTranslatef(drawBone.x, drawBone.y, drawBone.z); //最初のボーンはpositionから描画。次以降のボーンは前のボーンの先端から描画
//各ボーンデータのaxisVectorを軸に、rotationBoneAngleだけ回転させるクォータニオンを作成
qBoneAxis[i] = QuaternionRotationAxis(b[i].axisVector, rotationBoneAngle[i]);

//上位ボーンの回転クォータニオンから次々に合成していく(掛ける方向注意)
quat = MultiplyQuaternion(qBoneAxis[i], quat);

//回転クォータニオンでボーンを回転させる
drawBone = QuaternionToVector( MultiplyQuaternion( MultiplyQuaternion(quat , VectorToQuaternion(b[i].boneVector) ), QuaternionConjugate(quat)) );

glBegin(GL_LINES);

switch(i)
{
case 0:
glColor3f(1.0, 0.0, 0.0);
break;
case 1:
glColor3f(0.0, 1.0, 0.0);
break;
case 2:
glColor3f(0.0, 0.0, 1.0);
break;
}

glVertex3f(0.0, 0.0, 0.0);
glVertex3f(drawBone.x, drawBone.y, drawBone.z);
glEnd();
}

描画した時点で、b[i].boneVectorにボーンの初期姿勢のベクトルが格納されています。
そのベクトルをそのまま描くとボーンの初期状態が描くことができます。
今回はその初期姿勢を回転させて動かそうというものです。

QuaternionRotationAxis()で、各ボーンデータのb[i].axisVectorを回転軸として、指定した角度分回転させるクォータニオンを作成します。
そしてその次の行で回転クォータニオンを上位ボーンの回転クォータニオンと合成しています。
この合成によって上位ボーンの回転が、描画しようとするボーンに伝わった上で描画ボーンの回転をさせることができます。
つまり、描画するボーンより上位のボーンすべての回転クォータニオンを合成し、
そこに新たに描画ボーンの回転クォータニオンを合成するということです。
同じことを次々と下位ボーンにて行うことで、ボーンの回転ができます。


inserted by FC2 system