UnityのIKを使って足の位置と角度を地面に合わせる機能

今回はキャラクターの足の位置と角度を地面に合わせる機能を作ってみたいと思います。

今回

こちらの動画を参考にさせていただきました。

IKに関しては

UnityのIKを使ってキャラクターが物を運んでいるようなアニメーションを作成していきます。

の記事を参考にしてください。

今回の機能を作成すると、

↑のような感じで足を地面の位置と角度に合わせる事が出来ます。

片足が空中にある時は別途なんらかの処理を加える必要がありそうです。

まずは足の位置や角度を地面に合わせるやり方を考えます。

足の位置をアニメーションとは別に地面に合わせる必要があるのでIKの機能を使います。

地面に位置と角度を合わせるので、足が地面と接地している個所を調べる必要があります。
その為にPhysics.Raycastを使ってキャラクターの足から下にレイを飛ばし常に接地面を調べるようにします。

スポンサーリンク

足からレイを飛ばし地面の情報を取得するスクリプト

手のIKを使った時と同じようにキャラクターにレイを飛ばす位置を設定し、そこからレイを飛ばし地面と当たった位置と角度に足のIKを設定します。

ここまでは手のIKの時と同じ事をしています。

足のIKの場合、立っているアニメーションの時はレイの当たった位置にIKのウエイトを1にして位置を設定すればいいんですが、歩いている時や走っている時に常にウエイトを1にしているとヒザ神(ロンドンハーツから引用)のような動きになってしまうのでアニメーションの動きにしたがってウエイトを変更していく必要があります。

この処理は後でやります。

既存のキャラクターに足のIKを施すスクリプトFootIKを新しく作り取りつけます。

スクリプトを少しづつ見ていきます。

isUseIKは足のIKを使うかどうかで、インスペクタでチェックのオン・オフを出来るようにします。

rightFootWeightとleftFootWeightは両足のIKのウエイトを入れます。

rightFootPos、leftFootPosは両足の位置、rightFootRot、leftFootRotは両足の角度を入れます。

offsetは足を置く位置のオフ設置値です。

rayRangeは両足から下側にレイを飛ばす距離です。

isRightFootIKとisLeftFootIKはレイが地面に到達している時に足のIKを有効にします。

OnAnimatorIKはAnimatorControllerのレイヤーでIK Passにチェックを入れていると呼ばれるメソッドです。

両足からレイを下側に飛ばし、地面に接触していたらその位置と角度を保持します。

レイの当たった位置はhit.pointで得られますが、角度は上側の方向と接触面の表面の方向から計算した角度に自身の足の角度をかけて求めます。

得られた情報はそれぞれのフィールドに保持しておきます。

で右足のIKの位置を取得出来ます。

isUseIKがtrueならばアニメーションパラメータのRightFootWeightとLeftFootWeightから値を取得し、IKのウエイトに設定します。

RightFootWeightとLeftFootWeightはアニメーションカーブの値をそのまま設定します。

アニメーションカーブはこの後作成します。

アニメーションの再生位置によってIKのウエイトを変更する

アニメーションの再生位置でIKのウエイトを変更出来るようにします。

まずは立っている状態のアニメーションIdleの場合は常にウエイトを1にして、レイの当たった位置に足を合わせるようにします。

アニメーションのCurveを使うとアニメーションの状態によってアニメーションパラメータの値を変更出来ます。

またアニメーションパラメータの名前と同じ名前をCurveの名前に指定すれば、アニメーションパラメータの値にCurveの値がそのまま設定されます。

アニメーションカーブに関しては

Unityで使う当たり判定(コライダ)のサイズをアニメーションに応じて変更し、ジャンプ中のキャラクターのコライダのサイズを変更し狭い空間を通過出来るようにしてみます。

を参考にしてください。

まずはアニメーションパラメータを作成します。

footik5

上のようにRightFootWeightとLeftFootWeightと名前を付けます。

footik3

次にIdleの状態のアニメーションを選択します。

footik4

上がIdleに設定しているアニメーションです。これを選択し、インスペクタ上のCurveを作成します。

footik6

Curvesの+の部分をクリックしRightFootWeightとLeftFootWeightを作成します。
ここでつける名前はアニメーションパラメータと同じ名前にします。

値の部分を1と設定し、常に1になるようにします。
これでIdleのアニメーションのCurveの設定は終了です。

次に走るアニメーションのCurveを設定します。

歩くアニメーションにアニメーションカーブを設定

上のようにアニメーションの動きが見えるようにウインドウを動かしておきます。

Idleのアニメーションの時と同じようにCurveにRightFootWeightとLeftFootWeightというパラメータを作成します。

次に足の着地時はウエイトを1に、離れた時はウエイトを0になるようにCurveのパラメータを変更します。

まずは右足の着地時にRightFootWeightのウエイトを1にします。
アニメーションで右足全体が着地した地点を探します。

footik8

その部分を見つけたら、RightFootWeightのKeyを足すアイコンをクリックし、パラメータを1に設定します。
今回の場合はアニメーションの最初に右足着地しているので、Keyの追加をする必要はないかもしれません。

次に右足が離れる部分までアニメーションを移動します。

footik9

右足が離れる部分でRightFootWeightのKeyを追加し、パラメータを0に設定します。
右足が離れているアニメーションの間はウエイトを0に設定し、着地したら1に設定します。

足が空中にある間から着地までのちょっとの間はウエイトが0から1になめらかに遷移するようにします。
右足の設定が終わったら、左足の設定も同じようにしてください。

設定が終わったらUnityの実行ボタンを押してください。
足のIKがうまくいくか見てみましょう。

footik13

確認の為にIdle状態の時にRunのアニメーションを設定します。(キー操作なくアニメーションの動きを確認する為)
キャラクターをコピーしFootIKをOnにしたキャラクターとOffにしたキャラクターのアニメーションを比較し、本来のアニメーションと差異がないようにCurveのパラメータを設定していく必要があります。

設定が終わったらIdleのアニメーションをIdleに戻し、IKの部分を見ていきましょう。

出来たと思ったのに足が地面に届かない

footik10

んー、まったく出来ておりません・・・・(+_+)
右足は何となくレイの当たった位置に固定されているようですが、左足がレイの当たった位置に到達しません。

キャラクターを動かすスクリプトをOffにして、
キャラクターを選択し、TransformのYの位置を下げてみます。

footik11

上のように左足もうまく接地しました。

今度は地面をキャラクターを押し上げる感じで下から上に移動させます。

footik12

上のように足の位置が接地し、角度も地面に合っています。

つまり最初の画像ではRayが地面に当たっていてIKの設定もうまくいっているはずなのに、なぜうまく接地しないのかというと体の重心が右足部分を基点にしているから左足は伸ばしているけど地面に到達しない為です。

下から地面を上げた場合は到達点をキャラクターの足によせてるので問題が出ません。

足が地面に到達しないのはコライダの影響かも

足が空中に浮いてしまう場合もあるので、両足の距離を計算しコライダの位置を変更することで対応してみます。

処理を追加していきます。

isChangeColPosはコライダの位置を調整するかどうかの設定です。

distanceは右足と左足の距離の半分を入れます。

defaultCenterはコライダのCenterの位置の初期位置です。

smoothingはコライダの位置を調整する時のスピードです。

OnAnimatorIKメソッド内の最後に処理を追加し、アニメーションがIdle状態の時だけコライダの位置を調整する事にします。

Math.Roundを使って両足のY軸の位置を小数点以下2桁までに丸めて差の絶対値を計算します。

CharacterControllerのcenterの位置のY軸の位置をデフォルト値からdistanceの値を足して調整します。

Idleアニメーション以外の時はデフォルトの位置に戻します。

これで完成です。

地面となるゲームオブジェクトにはFieldレイヤーを設定し、確認してみてください。

終わりに

これでIKを使って足の位置と角度を地面に合わせる機能が完成しました。

以前は空中に浮いて見えてしまう時に強制で位置を調整してましたがやめました。

今回の修正である程度機能としては出来たのではないかと思います。

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます

コメント

  1. 匿名 より:

    これは質問と言うより要望なのですが…。

    「Rigdoll」というものをご存知でしょうか?
    モデルがダランダランになるやつですよね。

    それを、rigidbodyのaddforceでも使って上に飛ばしたとしましょう。
    そうすると、力抜けた人形みたいに落ちてきますよね。

    ここからが本題なのですが、
    「どんな態勢からでも地面に手を付き足を立て、起き上がる」という機能は作れそうですか?

    聞いといてなんですが、とても難しそうですね…。
    やっぱりそれ専用のアニメーションを用意するしか無いんでしょうか?

    • RagDollの存在は知っているんですが使った事はありません。(^_^;)

      試しにEthanに設定し使ってみました。

      RigidbodyとJointの設定を勝手に施してくれるんですね、キャラクターの通常のアニメーションはAnimatorで制御し、攻撃を受けた時にAnimatorを無効化しRigidbodyの物理挙動にまかせるんでしょうか。

      RagDollを設定したキャラをまともに動かすやり方さえわからないのであれなんですが・・・・、

      攻撃を受けた時にRigidbodyの物理挙動にまかせて地面に衝突した後、キャラクターからスクリプトでレイを前方、横、後方に飛ばしてキャラクターがどの方向を向いているかを調べ、その後Animatorを有効化し、該当するアニメーションを再生するという感じになるんでしょうか。

      このやり方だとうつ伏せ、仰向け、横倒しのアニメーションを作成し、体が地面に付いた時の体制から近いアニメーションを再生するという感じになるのでアニメーションを作る必要がありそうです。

      その時にターゲットマッチングで地面と手等は合わせる事は出来そうです。

      アニメーションを作らずIKやキャラクターの移動だけで立ち上がらせるのはなかなか難しそうですね・・・・。

      手をつき足を立てというのでなければ、攻撃を受けた時のボーンの位置と角度を保持しておき、ボーンの位置と角度をLerp等を使って元に戻すというのは出来ますが(スーッと機械的に元の位置に戻すだけ)・・・、

      お力になれず申し訳ありません。(._.)

  2. 匿名 より:

    最後のコード、rightFootWeightを二回定義しているのでエラー置きますよ

    • ご指摘ありがとうございます。(._.)

      修正しておきました。

      この記事の機能自体の見直しをしなくてはいけないんですが、今のところあまり動作がうまくいってないので、動作がうまくいったら全体的な見直しもしなければいけませんね・・・・(-_-)