前回

で上半身のアニメーションだけを変更させて、上半身が銃を持ったり構えたりした状態で歩いたり走ったりする事が出来るようになりました。
以前の記事で、

視点の上下をする機能を作りましたが、体の向きは変えていなかったのでカメラの視点とのズレが発生していました。
↑のような感じで視点(カメラの向き)は上下しても体の向きを変えていない為に銃口は前を向いたままになっています。
今回は銃を構えた状態で歩いたりする事が出来るようになったので、視点を上下した時に
体の向きを変えて銃口を視点の先に変更していきたいと思います。
上半身をカメラの向いている先に曲げる方法
やり方としては上半身の向きを変更し、カメラが向いている方向に向くようにしたいと思います。
フィールドでspineを宣言し、インスペクタで脊椎のボーンを設定出来るようにしておきます。
1 2 3 4 5 | // キャラクターの脊椎のボーン [SerializeField] private Transform spine; |
このspineの角度を変更する事で上半身の向きをカメラの向いている方向に向かせます。
ここでカメラの向いている方向と背のボーンの方向が違うので、そこはキャラクターのボーンの設定によって変更してください。
新しいメソッドRotateBoneを作成します。
1 2 3 4 5 6 | void RotateBone() { // 腰のボーンの角度をカメラの向きにする spine.rotation = Quaternion.Euler (spine.eulerAngles.x, spine.eulerAngles.y, spine.eulerAngles.z + myCamera.localEulerAngles.x); } |
MyCharaのUpdateメソッドに以下の処理を追加します。
1 2 3 4 | // ボーンをカメラの角度を向かせる RotateBone(); |
myCamera.localEulerAngles.xでカメラのX軸の角度を取得します。
腰のZ軸の角度にこのカメラの角度を足します。
カメラを上下させるとX軸の角度が変更する為、この変更度合いを背のボーンに加えています。
背のボーンではZ軸が上下に対応しているので、Z軸に足しています。
MyCharaのspineにEthanのSpine1のボーンをドラッグ&ドロップしてください。
↑のMyCharaはC#になっています(後で追加した画像の為)。
これで試しにUnityを実行して上半身が視点の上下で曲がるかどうか確認してみましょう。
スクリプトを記述しましたが上半身の角度が変わらずカメラの向きと合いません・・・(T_T)
Updateメソッド内でカメラの角度を変更していて、同じフレームでカメラの角度を使って上半身の角度を変更するのが良くないようです。
そこでUpdateメソッド内でカメラの角度を変更した後、LateUpdateメソッド内で上半身の角度を変更させるようにします。
上半身のボーンをLateUpdateメソッド内で変更する
LateUpdateメソッドはUpdateメソッドの処理が実行された後に実行されるメソッドです。
1 2 3 4 5 6 | void LateUpdate() { // ボーンをカメラの角度を向かせる RotateBone(); } |
↑のようにLateUpdateメソッド内で処理をします。
(MyCharaスクリプト内に記述してください)
それでは再度実行して試してみましょう。
上半身がカメラの角度分曲がるようになりましたが、そのせいでキャラクターの中身が見えてしまうようになりました。
Scene画面で確認するとMain CameraをEthanの直下に配置している為、上半身の角度が変わってもカメラの位置が変わりません。
カメラがキャラクターの中身を表示しないようにする
そこでMain CameraはEthan直下に残しつつ、カメラの位置を上半身の角度にそって移動するようにしましょう。
カメラは目の代わりなので、Ethanの頭(EthanHead1)の直下にダミーのカメラ位置を作成します。
EthanHead1を選択した状態で右クリック→Create Emptyを選択し、空オブジェクトを作成して名前をCameraPositionとします。
CameraPositionを移動し目の辺りに移動させます。
↑のような位置に移動させました(適宜変更してください)。
これでダミーのカメラ位置が出来上がりました。
上半身を曲げた時にこのダミーカメラ位置も相対的に動くようになります。
カメラの角度処理はMain Cameraに別のスクリプトを使ってCameraPositionの位置と角度を参照するようにしていましたが、カスタマイズする時に大変な為、処理を変更しました。(2017/08/17)
次にMyCharaスクリプトにcameraPositionというダミーカメラのTransform情報を保持するフィールドを宣言し、RotateCamera、RotateBoneメソッド内でmyCameraの角度を参照、直接変更していた箇所をcameraPositionの角度に変更し、LateUpdateメソッド内でRotateBoneメソッドを実行した後にカメラ位置を更新します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | // カメラのTransform [SerializeField] private Transform cameraPosition; // カメラの角度を変更 void RotateCamera() { float xRotate = Input.GetAxis("Mouse Y") * mouseSpeed; // マウスを上に移動した時に上を向かせたいなら反対方向に角度を反転させる if(cameraRotForward) { xRotate *= -1; } // 一旦角度を計算する cameraRotate *= Quaternion.Euler(xRotate, 0f, 0f); // カメラのX軸の角度が限界角度を超えたら限界角度に設定 var resultYRot = Mathf.Clamp (Mathf.DeltaAngle (initCameraRot.eulerAngles.x, cameraRotate.eulerAngles.x), -cameraRotateLimit, cameraRotateLimit); // 角度を再構築 cameraRotate = Quaternion.Euler (resultYRot, cameraRotate.eulerAngles.y, cameraRotate.eulerAngles.z); // カメラの視点変更を実行 cameraPosition.localRotation = Quaternion.Slerp(myCamera.localRotation, cameraRotate, rotateSpeed * Time.deltaTime); } void RotateBone() { // 腰のボーンの角度をカメラの向きにする spine.rotation = Quaternion.Euler (spine.eulerAngles.x, spine.eulerAngles.y, spine.eulerAngles.z + myCamera.localEulerAngles.x); } void LateUpdate() { // ボーンをカメラの角度を向かせる RotateBone(); // カメラの位置と角度を変更 myCamera.localRotation = cameraPosition.localRotation; myCamera.position = cameraPosition.position; } |
それではMain Cameraの位置が移動するようになったかUnityの実行ボタンを押して確認してみましょう。
↑のように視点を上下するとMain Cameraの位置も頭の位置と連動して動くようになりキャラクターの中身が表示されるという事がなくなりました。
IKのSetLookAtWeightを使って上半身をカメラの向きに変える方法
今回のようにキャラクターのボーンを操作しなくても、IKのSetLookAtWeight、SetLookAtPositionを使ってキャラクターの向きをカメラの方向を向かせるという方法もあります。
ただ、左手のIKを使って手の位置を調整している場合この方法は取れません。
左手だけ元の位置から動かなくなってしまいます。
↑のように左手が元の位置から動いていません。
左手のIKを使わずアニメーションの作成段階で銃をうまく持たせる事が出来ているならば左手のIKの機能であるHandIKを使うのをやめて
MyCharaスクリプト等に以下の処理を取りつけます。
1 2 3 4 5 6 7 8 9 10 | void OnAnimatorIK() { animator.SetLookAtWeight(1, 1, 1, 1, 1); Debug.Log(Camera.main.transform.forward); Debug.DrawLine(Camera.main.transform.position, Camera.main.transform.forward * 100, Color.red); animator.SetLookAtPosition(Camera.main.transform.position + Camera.main.transform.forward * 100); } |
↑のようにウエイトを設定し、カメラの位置からカメラの前方向の100m先の位置を見るように設定しています。
SetLookAtWeightに関しては

を参照してください。
またOnAnimatorIK関数のイベントを発生させるにはAnimatorのレイヤーでIK Passにチェックを入れている必要があります。
(前の記事をご覧いただいている方はチェックが入っているはずです)
今後はボーンの角度の変更で話は進んでいくのでIKで体の向きを変えている場合は記事の内容と変わってくる点にご注意ください。
終わりに
今回でキャラクターの動きが完成しました。
ようやくですね・・・・(^^)v
前回のFPSの記事から少し期間が開きましたね、この記事自体はずいぶん前に出来上がっていたんですが、FPS記事ばかりでもブログの記事内容が隔たってしまう為に
公開はしていませんでした。