【C++】DirectXにおける3Dアニメーションプログラミングを分析する~その4

今回はIKボーンによるボーン位置の再計算部分のロジックのみ抜き出してソースを解析した。

前回同様、解析内容はソースコメントという形で追記してある。

大まかな流れは下記のとおり。(あくまで俺の解釈なので間違ってる可能性あり)

それぞれ、
影響ボーン:IKボーンから連鎖数内にあるボーン
目標ボーン:目標とするボーン
IKボーン:目標ボーンに向かって移動するボーン
とすると、

あらかじめ読み込んでいたIKボーンをひとつずつ計算していくループの中で…

1.VMDデータに含まれる再帰演算回数分ループを行う。
2.影響ボーンの数のループを行う。(ik_chain_length)
3.影響ボーンを基準に目標ボーンとIKボーンのローカル座標に変換する
4.変換した座標に対して、影響ボーンを始点とするベクトルを算出する。
(影響ボーン→目標ボーン、影響ボーン→IKボーンの2ベクトル)
5.算出した2ベクトルの内積を計算して角度に変換する。
6.算出した2ベクトルの外積を計算して回転軸に変換する。
7.回転角度と回転軸が決定したのでIKボーンを回転する。

下記がそのソースとなる。(ひざボーンの調整ロジックは割愛してある)


//再帰演算回数分、IK演算を繰り返す
for (unsigned int culCount = 0; culCount < ikData.iterations; ++culCount) { //影響ボーンの回数分、IK演算を繰り返す for (unsigned int i = 0; i < ikData.ik_child_bone_index.size(); ++i) { //============================================================================= //ik_child_bone_index 影響ボーン:IKボーンから連鎖数内にあるボーン //ik_target_bone_index 目標ボーン:目標とするボーン //ik_bone_index IKボーン:目標ボーンに向かって移動するボーン //============================================================================= //影響ボーンのインデックス unsigned short attentionIdx = ikData.ik_child_bone_index[i]; //目標ボーンの位置 D3DXVECTOR3 effectorPos((*bones)[ikData.ik_target_bone_index].CalBoneMatML().m[3]); //IKボーンの位置 D3DXVECTOR3 targetPos((*bones)[ikData.ik_bone_index].CalBoneMatML().m[3]); //影響ボーン行列の逆行列 D3DXMATRIX invCoord; //逆行列の取得(基の行列の-1乗の行列) D3DXMatrixInverse(&invCoord, 0, &(*bones)[attentionIdx].CalBoneMatML()); //影響ボーン基準で目標ボーンのローカル座標を変換 //指定された行列により 3D ベクトルをトランスフォームし、その結果を w = 1 に射影する。 D3DXVec3TransformCoord(&localEffectorPos, &effectorPos, &invCoord); //影響ボーン基準でIKボーンのローカル座標を変換 //指定された行列により 3D ベクトルをトランスフォームし、その結果を w = 1 に射影する。 D3DXVec3TransformCoord(&localTargetPos, &targetPos, &invCoord); //影響ボーンから目標ボーンへのベクトルを算出 D3DXVECTOR3 localEffectorDir; //3D ベクトルの正規化したベクトルを返す。 D3DXVec3Normalize(&localEffectorDir, &localEffectorPos); //影響ボーンからIKボーンへのベクトルを算出 D3DXVECTOR3 localTargetDir; //3D ベクトルの正規化したベクトルを返す。 D3DXVec3Normalize(&localTargetDir, &localTargetPos); //ひざボーンの調整ロジック割愛 //目標ボーンへのベクトルとIKボーンへのベクトルの内積 //2 つの 3D ベクトルの内積を計算する。 float p = D3DXVec3Dot(&localEffectorDir, &localTargetDir); if (p > 1 – 1.0e-8f)
{
// 計算誤差により1を越えるとacos()が発散するので注意!
continue;
}

//内積を角度に変換してウエイトをかける
float angle = acos(p);

if (angle > 4 * ikData.control_weight)
{
angle = 4.0f * ikData.control_weight;
}

//目標ボーンへの方向とIKボーンへの方向の外積
//2 つの 3D ベクトルの外積を計算する。
D3DXVECTOR3 axis;
D3DXVec3Cross(&axis, &localEffectorDir, &localTargetDir);

//外積で求めた軸を回転軸にして、内積で求めた角度を回転する行列を作成する。
D3DXMATRIX rotation;
D3DXMatrixRotationAxis(&rotation, &axis, angle);

//ひざボーンの調整ロジック割愛

//影響ボーンを回転する
(*bones)[attentionIdx].boneMatBL = rotation*(*bones)[attentionIdx].boneMatBL;
}

const float errToleranceSq = 0.000001f;
//3D ベクトルの長さの 2 乗を返す。
if (D3DXVec3LengthSq(&(localEffectorPos – localTargetPos)) < errToleranceSq) { //IKによる移動量が閾値より小さい場合、IK演算を終了する return; } } [/csharp] [amazonjs asin="4797374543" locale="JP" title="入門ゲームプログラミング (Professional Game Developerシリーズ)"]

4年前

コメントを残す

メールアドレスが公開されることはありません。