公開日:2023/07/08  更新日:2023/07/08

Unityの足が浮くのをなおす方法

 前回までの記事で以下のように剣のコンボが可能となった。

 前回までの記事↓
TPSのキャラ移動
ジャンプ
ダッシュ実装
自作キャラを動き回らせる
剣を振る方法
剣コンボ

 実は今までキャラの足元は移さないようにカメラを配置していた。足元を映した途端にキャラの不自然さがあらわになってしまうからだ・・・
 足元をうつしてマウスを動かし空を見上げたり、地面を見下ろしたりしてみよう、見上げると以下のようになる。

 左足が浮く状態となっており、非常に不自然だ。
 同様に、見下ろすと以下のように右足が浮いてしまう。

 今回はUnityのIKと呼ばれる機能を使って、キャラのX軸の向きを変えて見上げたり、見下ろした場合の不自然さを解消する方法を紹介していく。

Unityでの足が浮くのをなおす方法目次

IKの基本と使い方
スクリプト記述
目次にもどる

IKの基本と使い方

 IKとはスケルトン構造を制御する機能。目標位置を決め、そこから逆算して骨の位置を調整することができる。
 具体的には、例えば足の末端の位置を決めることで膝や太ももを動かすといったことが可能。
 IKが使えるのはHumanoid、つまり人型(頭1つ、腕2つ、足2つ)のモデルに限られるので注意しよう。

 IKの使い方は以下の通り。

 IKで動かしたい3Dモデル(今回はPlayer)のAnimatorコンポーネントで指定しているAnimatorcontrollerを開く。
 Layersタブを選択しIKと書かれた部分の右にある歯車マークを選択する。

 すると以下のような画面が出るので「IK Pass」のチェックを入れよう。

 これでIKの機能が使えるようになった。
目次にもどる

スクリプトの記述

 IKの機能を使えるようにすると、OnAnimatorIKというメソッドを呼び出すようになる。
 よって、Playerにアタッチしているスクリプト内にOnAnimatorIKというメソッドを作り記述した。スクリプトは以下のようになった。
 

 メソッドのOnAnimatorIK()の記述を見ていく。

 if (Groundtuku == true)の条件分岐を行っているが、Groundtukuはジャンプできるかどうかの処理でジャンプ可能ならtrueがつくように記述している。地面についておりジャンプが可能な場合にのみIKが機能するようにしてある。
 float idouryou = anim.GetFloat("MoveSpeed");でMoveSpeedのパラメータを代入している。今回の足が浮く問題は特に静止時に顕著であるため、移動していない時によりIKが機能するようにするため、この記述をしている。

 次のrayiti = FootObjectR.position;からがIKを活用するための本格的な処理のはじまりとなる。
 IKの機能を使うなら目標位置を決める必要がある。今回は以下のように浮いてしまった足の真下を目標位置としたい。

 そのため右足を構成しているJ_Bip_R_Footから真下にRayを放ち、地面(Plane)に当たるまでの距離を求めていく。
 よって、以下のようにシリアル化を行ってJ_Bip_R_FootのTransform情報をFootObjectRに取得しておく。

 rayiti = FootObjectR.positionとしてFootObjectRの位置をrayitiに代入している。
 そして、Physics.Raycast(rayiti, rayhoukou, out rayzyouhou, 1f);としてある。rayhoukouにはVector3.downが代入されており、常に真下にRayが発射される。rayzyouhouの変数にRayを放った際の情報が入り、1fはRayを飛ばす距離を示す。
 raydistance = rayzyouhou.distance;とすることでRayを撃った位置からRayが当たった位置までの距離をraydistanceに代入できる。
 float raykeisan1 = rayiti.y - raydistance + 0.12f;としてRayを放った位置のY座標からraydistanceを引くことで、足の真下の目標位置のY座標を割り出すことができる(+0.12fは足が埋まらないための調整値)。
 FootObjectR.position = new Vector3(rayiti.x, raykeisan1, rayiti.z);として目標位置をFootObjectR.positionに代入。

 目標位置を決めることができたので、ここからIKの処理に入る。
 今回は移動停止時に足が浮くのが大きな問題となっている。よってif (idouryou == 0)と条件分岐している。
 idouryou == 0、つまり移動していない時にはanim.SetIKPositionWeight(AvatarIKGoal.RightFoot, 1.0f);の処理が行われる。SetLookAtWeightは体、頭、手足などの追従具合(重み)を指定できる関数だ。AvatarIKGoal.RightFootとして右足のIKを有効化することができる。1.0fという記述でIKの重みを決めている(重みは1.0fが最大)。元のアニメーションの位置を重視するなら0に近い値、目標位置を重視する場合は1に近い値を入れる。目標位置を重視するため今回は1.0fを入れた。
 一方でidouryou == 0ではなかった時のelseの処理ではanim.SetIKPositionWeight(AvatarIKGoal.RightFoot, 0.02f);としており、0.02という小さい数値にしている。

 続いて右足IKの目標位置を決める処理を行っている。
 anim.SetIKPosition(AvatarIKGoal.RightFoot, FootObjectR.position);として目標位置を記述している。
 anim.SetIKRotation(AvatarIKGoal.RightFoot, FootObjectR.rotation);として目標の回転を記述している。

 以上で右足のIK設定は終了であり、続いて左足でも同様の記述を行っている。

 スクリプト記述を行いPlayerにアタッチして再生すれば、以下のように足が浮くこともなくキャラを動かすことができる(カメラは足元が見えるよう、お好みの位置に調整しよう)。


Unityのゲーム制作まとめへ戻る

page top