普段からdxlibを使わせてもらってます。いれぶんといいます。
題名通り、モデルのボーンを特定の方向に向かせる方法がわからくて困っています。
以下のサイトや友人のコードを参考に作っているのですが、現状だと、回転させるボーンが上方向(ワールド座標から見て)に向きます。
どなたか実装方法がわかる方や間違っている原因などがわかる方がいましたら教えていただけると幸いです。
marupeke296.com/DXG_No64_CharacterPose.html
techblog.sega.jp/entry/sega_inverse_kinematics202210
以下のコードです。
//ボーンをターゲットの方向に向かせる
void HoldUpRightGunAnim::faceArmToTargetPosition(const std::shared_ptr<PlayerStatus> status)
{
const int modelHandle = status->getModelHandle();
const int lowerArmBoneIndex = status->getModelBoneIndex()["Rb_LowerArm_R"];
// 回転させるボーンの行列、座標を取得
const MATRIX frameWorldMatrix = MV1GetFrameLocalWorldMatrix(modelHandle, lowerArmBoneIndex);
VECTOR frameWorldPosition;
SetVectorFromMatrix(frameWorldMatrix, frameWorldPosition);
// 対象の方向を見る(今回はカメラの注視点を見る)
const MATRIX cameraTargetWorldMatrix = MInverse(GetCameraViewMatrix());
VECTOR cameraTargetWorldPosition = VTransform(VGet(0, 0, 10), cameraTargetWorldMatrix);
MATRIX lookAtMatrix = LookAt(frameWorldPosition, cameraTargetWorldPosition);
// ローカル行列に変換
const MATRIX parentWorldMatrix = MV1GetFrameLocalWorldMatrix(modelHandle, MV1GetFrameParent(modelHandle, lowerArmBoneIndex));
const MATRIX parentWorldRotationMatrix = MGetRotElem(parentWorldMatrix);
const MATRIX frameLocalRotationMatrix = MMult(MGetRotElem(lookAtMatrix), MInverse(parentWorldRotationMatrix)); //warn?
// ローカル行列に回転行列を設定
MATRIX frameLocalMatrix = MV1GetFrameLocalMatrix(modelHandle, lowerArmBoneIndex);
SetRotationToMatrix(frameLocalMatrix, frameLocalRotationMatrix); //warn?
// ローカル行列として適用
MV1SetFrameUserLocalMatrix(modelHandle, lowerArmBoneIndex, frameLocalMatrix);
}
/// <summary>
/// 特定の方向を見る行列を求める
/// </summary>
/// <param name="fromVector">求めたい方向の座標1</param>
/// <param name="toVector">求めたい方向の座標2</param>
/// <param name="upVector">上方向</param>
/// <returns></returns>
inline MATRIX LookAt(const VECTOR fromVector, const VECTOR toVector, const VECTOR upVector = axis_y)
{
const VECTOR fowardDirection = VNorm(VSub(toVector, fromVector)); //前方向(向くべき方向)
const VECTOR sideDirection = VNorm(VCross(upVector, fowardDirection)); //前を基準とした左右方向
const VECTOR correctUpDiretion = VNorm(VCross(fowardDirection, sideDirection));//前方向と右方向で正しい上方向を求める
//求めた3つの方向と見たい方向の元となる座標から回転と座標をセットすることでlookat行列を求める
const MATRIX lookAtMatrix = MMult(CreatRotationMatrixFromVector(sideDirection, correctUpDiretion, fowardDirection), MGetTranslate(fromVector));
return lookAtMatrix;
}
/// <summary>
/// 回転行列の値を行列にセット
/// </summary>
/// <param name="matrix">セットされる行列</param>
/// <param name="rotataionMatrix">セットする回転行列</param>
inline void SetRotationToMatrix(MATRIX& matrix, const MATRIX rotataionMatrix)
{
/*const VECTOR scale = MGetSize(matrix);*/
const VECTOR scale = VGet(1.0f,1.0f,1.0f);
//値をセットするだけだとスケールがぶっ壊れる?ので後からスケールをかけなおす
matrix.m[0][0] = rotataionMatrix.m[0][0] * scale.x;
matrix.m[1][0] = rotataionMatrix.m[1][0] * scale.y;
matrix.m[2][0] = rotataionMatrix.m[2][0] * scale.z;
matrix.m[0][1] = rotataionMatrix.m[0][1] * scale.x;
matrix.m[1][1] = rotataionMatrix.m[1][1] * scale.y;
matrix.m[2][1] = rotataionMatrix.m[2][1] * scale.z;
matrix.m[0][2] = rotataionMatrix.m[0][2] * scale.x;
matrix.m[1][2] = rotataionMatrix.m[1][2] * scale.y;
matrix.m[2][2] = rotataionMatrix.m[2][2] * scale.z;
}
/// <summary>
/// 3つのベクトルから回転行列を作る
/// </summary>
/// <param name="rightVector">右ベクトル</param>
/// <param name="upVector">上ベクトル</param>
/// <param name="forwardVector">前ベクトル</param>
/// <returns></returns>
inline MATRIX CreatRotationMatrixFromVector(const VECTOR rightVector, const VECTOR upVector, const VECTOR forwardVector)
{
//※dxlibのMATRIXは[行][列]
MATRIX rotationMatrix = MGetIdent();
rotationMatrix.m[0][0] = rightVector.x;
rotationMatrix.m[0][1] = rightVector.y;
rotationMatrix.m[0][2] = rightVector.z;
rotationMatrix.m[1][0] = upVector.x;
rotationMatrix.m[1][1] = upVector.y;
rotationMatrix.m[1][2] = upVector.z;
rotationMatrix.m[2][0] = forwardVector.x;
rotationMatrix.m[2][1] = forwardVector.y;
rotationMatrix.m[2][2] = forwardVector.z;
return rotationMatrix;
}
/// <summary>
/// ベクトルの値を行列にセット
/// </summary>
/// <param name="matrix">値をセットする行列</param>
/// <param name="vector">セットしたいベクトル</param>
inline void SetVectorFromMatrix(const MATRIX& matrix, VECTOR& vector)
{
vector.x = matrix.m[3][0];
vector.y = matrix.m[3][1];
vector.z = matrix.m[3][2];
}