バーチャル3Dクリエイター神部まゆみです(*^_^*)
この記事はUnityのアニメーションで足が浮く問題の対処法についての記事です。
やりたいこと:モーションキャプチャしたモーションが浮いていたので直したい
TDPTっていう画像認識系のモーションキャプチャーで撮影したモーションをUnityに持っていったら足が浮いてしまった。
まぁ最低限はblenderで位置調整したからそこまででもないけども。
これは配布モーションでもなるので設定とかの問題かな?
以前BVHファイルをunityに持ってきたときは「ルートモーションを適用」にチェックを入れたら改善されたけどちょっと浮いてましたね…。
RigidBodyで落とせば行けるかと思ったけどバランス崩して倒れたw
RigidBodyコンポーネントを追加すると重力が使えるので良い感じに接地させられるかと思いましたが、最初は良かったけどバランス崩して倒れましたw


まぁモーションとコライダーの設定によってはこれでも行けると思うけど、調整がめんどくさそうなのでスクリプトでなんとかできたらと思った。
足IKで接地させるスクリプト FootIKController
ChatGPTに聞いてみたところ、足からRayを飛ばして接地判定をするとコライダーよりも厳密な接地判定ができるっぽい。
スクリプトを書いてもらいました。
片足立ちにも対応させたので多分大丈夫だと思います。
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class FootIKController : MonoBehaviour
{
public LayerMask groundLayer;
public float rayLength = 1.2f;
public float footOffset = 0.1f; // 少しだけ浮かせると埋まらない
private Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void OnAnimatorIK(int layerIndex)
{
AdjustFootIK(AvatarIKGoal.LeftFoot);
AdjustFootIK(AvatarIKGoal.RightFoot);
}
void AdjustFootIK(AvatarIKGoal foot)
{
Vector3 footPos = animator.GetIKPosition(foot);
Ray ray = new Ray(footPos + Vector3.up * 0.3f, Vector3.down);
// 足が地面に近い or ヒットしたら補正
if (Physics.Raycast(ray, out RaycastHit hit, rayLength, groundLayer))
{
float footHeight = footPos.y - hit.point.y;
if (footHeight < 0.3f) // 足が30cm以内なら「接地している」とみなす
{
Vector3 targetPos = hit.point + Vector3.up * footOffset;
animator.SetIKPositionWeight(foot, 1);
animator.SetIKRotationWeight(foot, 1);
animator.SetIKPosition(foot, targetPos);
animator.SetIKRotation(foot, Quaternion.LookRotation(transform.forward, hit.normal));
return;
}
}
// 接地してないなら補正なし(浮いてる足をそのままに)
animator.SetIKPositionWeight(foot, 0);
animator.SetIKRotationWeight(foot, 0);
}
}
アニメーションのFootIKとレイヤーのIKパスにチェックを入れておく
足IKを使うにはこれが必要っぽい。


モデルにスクリプトをアタッチ、床オブジェクトのレイヤーを設定
モデルにスクリプトをアタッチして、床のレイヤーを設定します。


↓は床のオブジェクトだけど、ここにGroundレイヤーを作って設定しておきました。
ゲーム制作系のアセットとか使っている場合は、最初から接地処理のために作成されてたりするかも。


Foot Offsetで高さの微調整ができるけど、ちょっと浮かせた方が足がめり込まないので0.1くらいがちょうどいいかな。
モーションによってどのくらい浮いてるかも違うと思うので、Ray Lengthを調整すると良い感じになるかもしれない。
これで良い感じに接地できた!
これで良い感じに接地できましたね。片足立ちでも大丈夫です!
調整すれば膝立ちや座位でもこの方式で接地できるっぽい?
現状のスクリプトだと足からRayを出して接地処理をしているようなんだけど、調整すれば膝立ちや座ってる姿勢でも設置処理できるらしいです。




ありがとうございます。
とりあえず足、膝、腰だけ対応できれば9割以上大丈夫だと思うんですけど、現状の方式でスクリプト書き換えるだけで実装できますかね?


うん、それなら今の方式をベースにしてスクリプトを拡張するだけで全然いけます!
足→膝→腰と接地チェック用Raycastを追加するだけなので、手間も少なめです。以下の感じで対応できます!
しかしChatGPT氏、ホントに最近馴れ馴れしくなってきたな…(笑)。
まぁちょっと長くなりそうだからまた次回やろうかな(^_^;)
アニメーションファイルのRootだけ編集する場合、Umotion Proのレイヤー機能を使うとやりやすかった
アニメーションファイルだけで接地の位置調整したい場合はRootの位置をいじることになるけど、Umotion Proだとレイヤー機能でRootだけ上書きできるのでやりやすかったです。
手打ちならともかく、特にモーションキャプチャーのデータってRootありきでフレームごとのポーズが表現されてる感じなので、レイヤー使わないで編集するとアニメーションが破綻する可能性がありますね…。
簡単なアニメーションやポーズを手打ちで作るならVeryAnimationが使いやすいけど、アニメーション改変用にUmotion Proがあると便利です。
つづく?
案外簡単に接地できて良かった。
次回できるようなら膝や腰の設置もやってみようかな。
まぁもう少しいじってみます(*^_^*)