今回はHandIKを使って、壁に近づいたら壁に向かって手を着くという処理を作っていきます。
挑戦と言っても、前回までのFootIKよりも簡単に実装できてしまうので、FootIKの実装の復習として見て頂ければと思います。
ソケットの追加
FootIKの手順と同じで、手の位置の正面の壁を検出する為のソケットを追加していきます。(詳しい手順はFootIKの解説を参照してください。)
追加するソケットは”upperarm_l”と”upperarm_r”の位置で、それぞれ名前を”SocketUpperarmL”と”SocketUpperarmR”としました。

ライントレース処理の追加
先ほど追加したソケットから正面方向にライントレースを飛ばして壁を判別します。
IKHandTraceという関数を追加し、処理は以下のように組みました。基本的にIKFootTraceと似ていますが、今回はキャラクターの前方にライントーレスを飛ばすので、GetActorForwardVectorノードでグレイマンの正面方向を取得し、引数で指定されたDistanceの距離を掛けることで、ライントレースの距離を決めています。
また、今回は手を壁に付いているか否かを判断する必要があるので、戻り値にBoolean型のHasHitWallを追加しています。

ブループリントインターフェースを用意
FootIKの時に、足の位置をアニメーションBPに渡す為にブループリントインターフェースを利用しましたが、今回もブループリントインターフェースで手を壁に付けるか否かと、その座標をアニメーションBPに渡していきたいと思います。
FootIKの時に作成したBPI_ThirdPersonFootIKにHandIK用の関数定義をしましょう。関数名はUpdateHandIKとしました。(ブループリントインターフェース名にFootIKを入れたのは間違いでしたが、そのまま突き進みます)

Tick処理でライントレース処理を呼び出す
ThirdPersonCharacterのイベントグラフのTickでIKFootTraceを呼び出している処理がありましたが、その後にIKHandTraceを呼び出すようにしてみます。ここも、ほぼほぼFootIKと同じような処理になります。強いて言えば、Boolean型のHitWallを扱うようになった点が異なるくらいでしょうか・・・

アニメーションBPのイベントグラフで手の座標を受け取る
これも、FootIKと同じような処理になりますが、アニメーションBPのイベントグラフ内にUpdateHandIK関数をオーバーライドし、ThirdPersonCharacterから受け取った情報をアニメーションBPに追加した変数に格納していきます。

アニメーションBPのAnimGraph
さて、ここからが、HandIK処理の一番難しい部分となります。
基本的にFootIKで制御した「足」は常に地面に触れている為、FootIKのTwoBoneIKノードは如何なる時も処理していましたが、今回のHandIKは壁が近い時だけ壁に向かって手を着くという処理になります。つまり、HandIK用のTwoBoneIKを動かしたり、動かさなかったりする状況が存在します。
また、壁に手を着く時は、手のひらの向きが壁を押している必要があるので、手を回転させる必要があります。
これらの問題を一つずつ問題を解決していきましょう。
手を壁に着けて回転させる
まずは、簡単に実装できそうな手の回転から実装していきます。
実はFootIKの時にも使った”ボーンをトランスフォーム(修正)する”ノードを使えば一発解決です。FootIKの時はボーン全体の位置を移動させたかったので、このノードのTransformを使用しましたが、今回は手を回転させたいので、Rotationを使用します。
例えば、左手の操作を行うTwoBoneIKノード組み合わせると、次のような処理になります。

TwoBoneIKのパラメータの詳細は以下の通りです。IKBoneには当たり前ですが、左手となる”hand_l”を選択しています。ここで超重要な設定値はEffectorLocationSpaceで選択している”World Space”になります。今回、Effectorに与えられるLocationは壁に衝突した座標となるので、ワールド座標がそのまま与えられます。ということで、TwoBoneIKで移動させる手の位置もワールド座標で指定することを宣言しています。

トランスフォームノードの設定値は以下の通りです。ここのノードでは手を回転させる処理を行っています。回転させる角度は固定値で指定し、Bone to Modifyには回転させる左手のボーンを選択しています。
(右手のHandIKについてはご自身で実装してみてください。手の回転方向が左手と異なりますが、試行錯誤してみると回転について理解が深まると思います)

壁に近づいた時だけHandIKさせる
上記のノードで、壁面にHandIKする処理は完成しましたが、この処理は壁に近づいた時だけ動作して欲しいという事を忘れてはいけません。つまり、ブランチノードのような条件分岐を噛ませて、HandIKのノードを通るようにしないといけないのです。
しかも、HandIKだけではなく、FootIKも有効にしたまま動かす必要があります。
そこで使用するのが、「ポーズのキャッシュ」ノードと、「ボーン毎のレイヤーブレンド」ノードです。簡単に説明すると、アニメーションのポーズを一時的に保存し再利用する為の仕組みが「ポーズのキャッシュ」で、特定のボーンの配下のみをアニメーションに適用する仕組みが「ボーン毎のレイヤーブレンド」となります。
まずは、ステートマシンから出てきたばかりのポーズをキャッシュしてみましょう。Defaultステートマシンから線を引っ張って”Cache”と入力すると「新規のキャッシュされたポーズ」ノードが一覧に表示されるので、それを選択します。このノードは最初に適当な名前が付与されているので、”DefaultCache”という名前にしておきました。

で、キャッシュしたポーズを呼び出すノードから出力ポーズノードに線を繋ぎます。右クリックして”DefaultCache”と入力すると、「キャッシュされたポーズを使用”DefaultCache”」というノードが作成できるので、そこから出力ポーズに線を繋げてください。

この状態でプレイしてみると、FootIKも、HnadIKも動かない状態でグレイマンが動き出します。つまり、ステートマシンで処理されたポーズがそのまま出力ポーズになっているという事です。
次に、FootIKの結果をキャッシュしてみましょう。元々FootIKの処理はDefaultステートマシンと出力ポーズに挟まれていましたが、今回はDefaultCacheと新規のキャッシュノードとして作成したFootIKCacheで挟んでみました。

そして、FootIKCacheから出力ポーズに線を繋いでみましょう。

この状態でプレイしてみると、正常にFootIKが動作するはずです。この流れで、ポーズのキャッシュの意味が理解できるかと思います。ステートマシンからDefaultCacheにキャッシュされたポーズは、FootIKの処理を実行し、FootIKキャッシュに格納されます。そして、その結果が出力ポーズとなるのです。
ということで、キャッシュの仕組みを使って左右のHandIKもポーズに含めていきましょう。
全ての開始ノードはDefaultCacheノードとし、”LeftHandIKCache”と”RightHandIKCache”にキャッシュしましょう。すると、こんな感じのノードになると思います。

最後に、”FootIKCache”・”LeftHandIKCache”・”RightHandIKCache”をまとめて出力ポーズに出力したいところですが、その前に”壁に近づいた時のみ”という条件を入れる必要があります。これには「ブレンド Poses by bool」というノードを使用します。簡単に言えば、Boolean値でポーズを切り替えるという処理です。
Boolean値であるIKLeftHandHitWallによって、左手側が壁に近づいているか否かを判断し、近づいている場合はHandIKを反映させたポーズを、壁から遠い場合はDefaultCacheのポーズ(つまり、ステートマシンから出てきたそのままのポーズ)を結果として出力するノードとなります。

これが、左右の手それぞれの処理がありますので、以下のようになります。

最後に「ボーン毎のレイヤーブレンド」ノードを使って、”FootIKCache”と、上記の両手のポーズを結合していきます。各キャッシュしたポーズを適用範囲毎にブレンドして最終的なポーズを作成してくれる、夢のようなノードを使えば、今まで作ってきたポーズを良い感じに合成してくれます。右上のコンフィグパネルでブレンドするボーンの基準を指定している点に注意してください。

最後に、このノードで作られた最終ポーズを出力ポーズノードに接続します。

これで、HandIKの実装が完了しました。プレイしてみると、壁に近づいた時だけ、壁に手を着けます。
あれ?これが有名な「壁ドン!?」ということで、グレイウーマンを配置して、壁ドンしてみましょう。
無事にハッピーエンドを迎えることが出来ました!!
これで、IK入門編はいったん終了となります。皆様のIKの理解に少しでも役に立てればうれしいです。
No responses yet