本稿では、Unreal Engine(以下 UE) 5 のサードパーソンテンプレートに含まれているアニメーションブループリント(ABP_Manny)の内容を詳しく読み解いていきます。
アニメーションブループリントは、AnimGraph とイベントグラフのふたつの機能を持っていますが、本稿では AnimGraph のみ扱います。
環境は以下。
Unreal Engine 5.3.1 および 5.4.2
Windows 11 Home
Visual Studio 2022
- テンプレにアニメーション追加しようと思ったけど、ひとつも分からん
- そもそも、ABP_Manny がどこにあるのか分からない。
- ひとつずつ解き明かしていく
- Locomotion (ロコモーション)
- Locomotion ノード
- UE5 で追加されたステートエイリアス
- おつかれちゃーん
- Slot (スロット)
- Control Rig(コントロールリグ)
- エンジニアに質問:時間かけて勉強しなくても、エンジニアなら C++ で AnimGraph みたいなもの作れるでしょ?
- エンジニアに質問:AnimGraph をコードで書かないなら学習する必要はないのでは?
UE5 のプロジェクトをサードパーソンで作成して、ABP_Manny を開いてみたんですが、AnimGraph がもう既に意味不明でした。
移動やジャンプはできますが、これに近接攻撃やパルクールのような動きを追加したい場合に、どうしたらいいのか分かりません。
ひとつひとつ地道に調べて、使い方を覚えていくしかなさそうです。
UE 自体をほとんど触ったことがない方のために、ABP_Manny にアクセスするまでの手順を説明します。
長いので、読みたい方は以下のスポイラーを選択して内容を表示してください。
UE 初心者が読むことも想定しているため、細かい話に入る前に、大まかな話をします。
アニメーションブループリントの概要について知りたい方だけ、以下のスポイラーを選択してご覧ください。
ロコモーションとは、移動(歩く、走る、旋回など)に関わるアニメーションの総称です。
ABP_Manny の AnimGraph を開くと、2つの Locomotion が並んでいるのが分かります。
左がステートマシン、右がノードです。
左にあるステートマシンの詳細は隠ぺいされています。
ステートマシンの詳細を確認するには、ダブルクリックする必要があります。
Locomotion ステートマシンの中を覗いてみます。
Locomotion ステートマシンをダブルクリックすると、ステートマシンっぽいグラフが表示されます。
↑の画像では余計な情報が多いので、重要な部分だけ抜き出すと以下になります。
Locomotion ステートマシンは Idle(待機)と Walk/Run(歩く、または、走る)の2つのステートだけ持っていることが分かります。
ステートマシンの評価は Entry から始まります。
Entry から Idle に向かって矢印が伸びているので、そのまま Idle に行きます。
Idle に遷移するための条件はありません。
Entry に来たら必ず Idle に遷移します。
Idle と Walk/Run はお互いに矢印が伸びています。
1. Idle から Walk/Run に遷移する。
2. Walk/Run から Idle に遷移する。
Locomotion ステートマシンは、このどちらかの遷移しか行わないということになります。
これらの矢印は、上下に丸いアイコンが付いていますが、遷移条件を設定していると、このアイコンが付きます。
アイコンをポイントすれば遷移条件が表示されます。
↑の画像にある「トランジションルール」とは、「遷移条件」のことです。
「遷移条件」が一致したときだけ、矢印の方向へ進む…ということになります。
遷移条件は ShouldMove という名前の何か…を使って行われることが分かります。
ShouldMove は、日本語にすると、「移動するべき」となります。
NOT ShouldMove の NOT は否定の意味なので、「移動するべきでない」となります。
Idle は「待機」
Walk/Run は「歩く/走る」
「移動するべき」とき、「待機」から「歩く/走る」へ遷移する。
「移動するべきでない」とき、「歩く/走る」から「待機」へ遷移する。
Locomotion ステートマシンの遷移処理についてイメージはつかめたので、まだよく分かっていない ShouldMove について調べてみます。
ShouldMove は遷移状条件に設定している「何か」なので、遷移条件を詳しく見てみます。
矢印の上にある丸いアイコンをダブルクリックすると、遷移条件を設定しているブループリントが表示されます。
そこに ShouldMove があるので、クリックして「詳細」を確認。
ブループリントの変数ですね。
「変数とは何か?」…は、知らなくても問題ありません。
マイブループリント > 変数 > Essential Movement Data で定義されています。
※マイブループリントが見当たらない場合は、こちらのスポイラーを展開して最後の方(ABP_Manny の AnimGraph を確認するまでの詳細な手順を表示する > AnimGraph がない、間違って閉じてしまったとき)をご覧ください。
ShouldMove は Boolean(ブーリアン)の変数なので、True(真)か、False(偽)か、2つの状態だけ持ちます。
ShouldMove の値が変わったときに、Idle ステートと、Walk/Run ステートの状態が切り替わります。
ShouldMove のような変数の使い道を理解するには、以下の2つのステップで調査を進めます。
- 変数の値を変更している場所を突き止める。
- 変数の値を変更する理由(条件)を理解する。
⇒ 変数の使い道が分かる。
まず、1について調べます。
変数がどこで使われているかは、検索できます。
Ctrl + F で検索欄を開き、ShouldMove と入力して Enter
Set 変数名 と書かれているところで値を書き換えています。
書き換えている場所は、そのすぐ上に表示されています。
ShouldMove は「イベントグラフ」のどこかで値を書き換えているようです。
検索結果をダブルクリックすることで該当箇所を確認できます。
検索結果の Set ShouldMove をダブルクリックしたところ、イベントグラフの↑の画像のブループリントが表示されました。
↑の画像のブループリントを見た感じ、移動のための入力を行い、移動量が閾値を超えることで、 ShouldMove の値が True になるようです。
ゲームパッドを使う場合、サードパーソンシューターのキャラクターは、左のアナログスティックを倒したときに、倒した方向に移動します。
※ボタン割り当てを変更できるゲームもありますが、通常はそうなります。
アナログスティックは人の指先では感知できないほどのわずかな入力も検出できます。
そのわずかな入力でキャラクターが移動してしまうと、ゲームをプレイするユーザーは「何もしてないのに勝手に移動した。」と感じることになります。
そのため、ある程度アナログスティックを倒すまでは移動しないようにする必要があります。
この「ある程度」というのが、移動量の閾値です。
↑の画像の中にある Ground Speed > 3.0 という条件が、その閾値を判定している処理になります。
もうひとつの Get Current Acceleration は、入力の加速度を調べていますが、これは 0 より大きいかどうかだけ判定しているので、閾値とは関係ありません。
2つの条件を合わせると、以下のようになります。
移動のための入力がある、かつ、 Ground Speed の値が 3.0 より大きいとき、 ShouldMove が True(真)になる。
それ以外は False(偽)になる。
移動のための入力はアナログスティックとは限りません。
キーボード操作の場合、移動のための入力は「押す」か「押さない」かの2値になります。
※アナログ入力を検出できる珍しいキーボードもあるかも知れませんが、一般的ではないので除きます。
入力が「ある」か「ない」かしか見ていないのは、アナログスティックでも、キーボードでも、どちらを使っていたとしても、この処理で判定できるからです。
これで対応できない状況もあると思いますが、入門者向けのテンプレートとしては、これで十分です。
※作るゲームが明確になり、操作感を突き詰めていく段階になったときに、この処理では対応できなくなると思いますので、そのときに「改造」すれば良いです。
「 Ground Speed ってなに?」と思うかも知れませんが、直訳すると「地上の速度」になります。
ジャンプ中や落下中をのぞいた、地面の上や、何らかの床の上、足場の上にいるときの移動スピードのことだろう…という推測ができます。
ShouldMove については分かったので、 Ground Speed については掘り下げません。
気になるようであれば、ShouldMove と同じように検索して調べてみてください。
以下はゲームデザインに関する補足です。
興味がある方は、スポイラーを展開してご覧ください。
Idle から Walk/Run へ「遷移する条件」は分かりました。
あと分かっていないのは、「Idle と Walk/Run ステートで何をしているのか?」です。
AnimGraph の中にあるステートマシンを評価した結果、行きつく先は Output Pose です。
アニメーションのどの位置(フレーム)を再生するのかをステートマシンで評価して、今ゲームが処理している1フレームで表示するべきアニメーションの1コマを決めます。
それが Output Pose です。
なので、Idle や Walk/Run など、ステートの中では、何らかのポーズを決めているはずです。
Idle ステートをダブルクリックすれば、Idle ステートが何をしているのかが分かります。
↑の画像は Idle ステートをダブルクリックして遷移した画面です。
※クリックするかタップすると大きい画像で表示できます。
アニメーションシーケンスの MM_Idle を再生しているだけです。
Output Animation Pose は各ステートの最後に配置します。
ステートマシンの中にあるステートの出口が Output Animation Pose です。
Output Animation Pose は、更に別の Output Animation Pose とブレンドする場合があります。
色々ブレンドした結果が Output Pose に出力されます。
ステートの出口が Output Animation Pose で、AnimGraph の出口が Output Pose です。
MM_Idle はサードパーソンテンプレートのマネキンで作られた待機アニメーションです。
デフォルトではアニメーションブループリント編集画面の右下「アセットブラウザ」にあります。
ここからドラッグ&ドロップすることで、ステート内に配置できます。
※本稿は読み解くのが目的ですので、編集はしません。
アセットブラウザが見当たらない場合は、メニュー>ウィンドウ>アセットブラウザ を選択することで表示できます。
Idle ステートと同じように、Walk/Run ステートをダブルクリックすることで、ステートの中身を確認できます。
こちらは Idle ステートと違い、アニメーションシーケンスをそのまま Output Animation Pose に繋いでいません。
ブレンドスペースと呼ばれるものを使っています。
ブレンドスペースは簡単に言うと、複数のアニメーションシーケンスを混ぜ合わせる機能です。
Walk/Run ステートで混ぜ合わせるのは、歩くアニメーションと走るアニメーションです。
どれくらい混ぜるか?を決めるのが、 Ground Speed です。
Ground Speed はキャラの足が床や地面に着いている状態での移動スピードです。
したがって、移動スピードによって、歩くアニメと走るアニメの混ざり方が変わります。
移動スピードが遅いときは、歩くアニメに近くなり、速いときは走るアニメに近くなります。
デフォルトでは2軸のブレンドスペースになります。
1軸のブレンドスペースを作成したいときは、アニメーション>レガシー>ブレンドスペース1D を選ぶ必要があります。
本稿ではブレンドスペースについては、これ以上は触れません。
公式ドキュメント参照。
ここまでで、AnimGraph では、アニメーションシーケンスの再生方法が2種類あると分かりました。
- 1つのアニメーションシーケンスを再生することができる。
- ブレンドスペースで複数のアニメーションシーケンスを合成したものを再生することができる。
Locomotion ステートマシンについては分かったので、また AnimGraph の最初の画面に戻ります。
次は、Locomotion ステートマシンの右隣りにある、Locomotion ノードについて調べます。
厳密に言うと、Locomotion ノードというノードはありません。
これは「キャッシュされたポーズ」に Locomotion という名前を設定したものです。
このノードは、Animation > Cached Poses カテゴリーにあります。
AnimGraph の何も配置していないところを右クリックすることで、AnimGraph に配置できるノードの一覧が表示されます。
ここから選ぶことができます。
これは、左にある Locomotion ステートマシンの結果をキャッシュ(メモリに保存)しておくためのノードです。
キャッシュしておくことで、ABP_Manny の AnimGraph 内ならどこでも Locomotion ステートマシンの「結果」にアクセスできます。
「結果」というのは、ステートマシンで様々なパラメータを参照して遷移先のステートが決まった状態を指します。
Locomotion ステートマシンに遷移するわけではなく、Locomotion ステートマシンで処理した結果をキャッシュします。
この仕組みを使うことで、複雑になりがちなステートマシンを綺麗に分かりやすく作ることができそうです。
そうすることで、「武器で攻撃するステートマシン」が必要になる度に、同じステートマシンをコピペする必要がなくなり、コピペしないよう巨大で複雑なステートマシンに含めておく必要もなくなります。
巨大で複雑なステートマシンとは別の場所に作っておいて、必要なときに呼び出すだけで済みます。
巨大で複雑なステートマシンが引き起こす問題について興味がある方は、以下のスポイラーを選択して内容をご覧ください。
ステートマシンをキャッシュしたい場合は New Save cached pose… を選び、そのノードに接続します。
「ノードの名前」は変更できます。
分かりやすい名前を付けた方が良いです。
近接攻撃ステートマシンの結果をキャッシュするなら MeleeAttack
…など。
New Save cached pose… を使って、キャッシュしたノードを使いたい場合は、Use cached pose ‘ノードの名前‘ を選びます。
サードパーソンテンプレートの ABP_Manny でどのように使われているのかを確認することで、使い方が分かるかも知れません。
ABP_Manny の AnimGraph を開くと、Locomotion ステートマシンと、Saved cached pose ‘Locomotion’ ノードが繋がっています。
↑の画像は、この記事の冒頭でも登場しましたが、赤枠で囲った中のことです。
Locomotion ステートマシンの結果をキャッシュ(保存)していますが、この「キャッシュ」をどこで使っているのか?…については、まだ調べていません。
ABP_Manny の AnimGraph にあるステートマシンは Locomotion と Main States の2つだけです。
「キャッシュ」を使っているのは、どちらかのステートマシンの中ということになりそうです。
Locomotion ステートマシンの中で Locomotion ステートマシンの結果にアクセスする…というのは、エンジニア視点だと循環参照になってフリーズしないか心配になる設計なので、本能的に避けます。
Locomotion ステートマシンの中で「ない」なら、Main States の中だろう…と予想できます。
Main States ステートマシンの中を調べ、Locomotion ステートマシンのキャッシュを探してみます。
AnimGraph の Main States ステートマシンをダブルクリック。
↓
Main States 直下にはないので、とりあえず、Locomotion ステートをダブルクリックして、更に奥へ。
↓
ありました。
左側にあるノード Use cached pose ‘Locomotion’ が Locomotion ステートマシンのキャッシュです。
Main States ステートマシンの Locomotion ステートに遷移することが決まったら、Locomotion ステートマシンのキャッシュが使われることになります。
キャッシュはステートマシンの結果を保持しているので、Locomotion ステートマシンを評価したのと同じ結果が得られることになります。
キャッシュを使っているのが一か所だけだと、キャッシュの有用性が分かりにくいです。
2か所以上でキャッシュを使ってみないことには、「なんでこんなややこしいことしてるの?」と思ってしまいます。
キャッシュの有難みを理解するために、具体例を考えてみます。
ステートマシンの中に、別のステートマシンを作ることができます。
これを利用して、Main States > Locomotion ステートの中に、Locomotion ステートマシンをコピペします。
キャッシュを使わなくても、これで問題なく動作します。
キャッシュを使う場所が1つしかないなら、これでも問題ありませんが、ABP_Manny が Use chached pose ‘Locomotion’ を使っているのは、ここだけではありません。
Main States > Land ステートの中でも使っています。
ここにあるキャッシュも Locomotion ステートマシンをコピペして繋ぎ変えます。
これによって、以下の3か所に、中身が同じ Locomotion ステートマシンが存在することになりました。
- AnimGraph のトップ
- AnimGraph > Main States > Locomotion ステート内
- AnimGraph > Main States > Land ステート内
中身は同じですがコピーして複製したものなので、どれか1つに変更を加えたとしても、残りの2つには何も影響しません。
仮に、Locomotion ステートマシンに機能を追加する必要が出たとします。
その場合、コピペした3か所全てを修正する必要が出ます。
逆に、キャッシュを使った場合、Locomotion ステートマシンは1か所にしか存在しません。
残りの2か所は、Locomotion ステートマシンの結果をキャッシュしたものです。
Locomotion ステートマシンの結果が変われば、キャッシュの中身も変わります。
したがって、キャッシュを使えば1か所を修正するだけで済みます。
ステートマシンを修正したときに、無駄な作業を発生させないようにするには、キャッシュを上手く使うことが重要ということになります。
Main States ステートマシンのトップに戻ります。
ここまでスルーしていましたが、このステートマシン、おかしくないでしょうか?
ステートマシンは Entry から評価が始まりますので、下にある2つのステートは Entry からたどることができます。
ところが、上にある3つのステートは、下にあるどのステートとも線で繋がっていないので、たどりようがありません。
よく見ると、To Land と、To Falling は頭についているアイコンが違います。
名前も To(~へ)と…どこかへ遷移するかのような名前がついているので、なんとなくステートとは違うものだろう…という予想はできます。
|
|
予想通り、To Land と、To Falling は、UE5 で追加されたステートエイリアスと呼ばれるものです。
AnimGraph を見ても、上と下のステートマシンの間には隙間があり、線は繋がっていませんが、実はこの2つは他のステートと繋がっています。
Main States ステートマシンはパッと見、Locomotion ステートから他のステートに矢印が伸びていないので、「どうやって Land や Jump に遷移するんだ?」と思ってしまいます。
ステートマシンは Entry から評価が始まるので、Entry → Locomotion と遷移して、そこで止まってしまうように見えます。
To Land と To Falling がどのステートと繋がっているか?は、それぞれをクリックして「詳細」を見ることで確認できます。
文字だと分かりにくいので、図にします。
To Land と To Falling がどこのステートと繋がっているのかが明確になりました。
ただ、どっちの方向に遷移するのか?が分かりません。
ステートエイリアスには、遷移条件も遷移する方向も指定できないので、おそらく、双方向に繋がるのではないかと思われます。
※遷移条件については後述します。
こうなりますが、他のステートの矢印の方向をたどると、遷移する方向は自ずと決まりそうです。
Entry からたどってみます。
Entry → Locomotion → To Falling
Entry → Locomotion → To Falling → Jump
Entry → Locomotion → To Falling → Fall Loop
Entry → Locomotion → To Falling → Land
? → To Land → Land → To Falling
Jump と Fall Loop から To Falling に向かっている矢印はありません。
したがって、To Falling の遷移する方向は以下の3つです。
Entry → Locomotion → To Falling
Entry → Locomotion → To Falling → Land
? → To Land → Land → To Falling
この時点では、Entry から To Land に遷移するパターンが不明なのでモヤっとしますが、To Land への遷移方法は次の項で確認します。
Entry → Locomotion → To Falling → Jump → To Land
Entry → Locomotion → To Falling → Fall Loop → To Land
Land から To Land に向かっている矢印がないので、To Land を経由する遷移パターンは上記の2つだけです。
実際はこのようなステートマシンになっているということが分かりました。
ただ、ステートエイリアスへの遷移条件が分かりません。
これはおそらく、「ない」が正しいと思います。
ステートエイリアスへの遷移条件はなく、ステートエイリアスから他のステートへ遷移するときに、その遷移条件が評価されます。
以下は公式のドキュメントにある「ステートエイリアスを使わない場合の遷移図」ですが、これと一致します。
ステートエイリアスが間に入っているので分かりにくいですが、実際は以下のように繋がっていることが分かります。
Locomotion → Jump
Locomotion → Fall Loop
Jump → Land
Jump ← Land
Fall Loop → Land
Fall Loop ← Land
よく見比べてみてください。
ここまでで、AnimGraph の説明はほぼ終わりです。
あとは、スロットとコントロールリグについてですが、これらはどちらかというと、アニメーションモンタージュやシーケンサー、IKリグの制御に必要なものなので、簡単な説明にとどめます。
アニメーションはスケルトンのボーンを回転させたり、移動させたりして行いますが、スロットは複数のボーンをまとめたものです。
上半身だけ、右腕だけ、左足だけ…など、複数のボーンに別のアニメーションを割り当てたいときに使います。
詳しくは公式のドキュメントをご覧ください。
アニメーションブループリントの仕組みを把握するため、サードパーソンテンプレートは使用せず、いちから AnimGraph を作ったことがあります。
その時はスロットノードの必要性が分かっていなかったので、繋いでいませんでした。
その状態でアニメーションモンタージュを作成し、再生したけど動かない…なんていうミスをして少し悩んだことがあります。
アニメーションモンタージュの動作には、最低限「DefaultSlot」を AnimGraph で繋ぐ必要があります。
新しくスロットを追加したら、DefaultSlot に加えて、追加したスロットを AnimGraph で繋ぐ必要があります。
それ忘れると、スロットを使ったアニメーションが再生されません。
アニメーションブループリントは、ブループリントのシステムで動きますが、コントロールリグは別の仕組みで動くアニメーションです。
そのため、アニメーションブループリントでコントロールリグを使う場合、Control Rig ノードを AnimGraph に繋ぐ必要があります。
簡単に違いを確認できる方法としては、IKリグです。
以下は、AnimGraph の Control Rig ノードを繋いだ状態(IKあり)と、繋いでいない状態(IKなし)での比較になります。
IKあり |
IKなし |
C++ で似たような機能を作れるか?作れないか?と言われた場合、作れます。
作れますが、UE エディタの仕組みに合わせて作ろうとすると、スレートの仕組みを把握するための調査から始める必要があるので、とてつもない時間がかかります。
とてつもない時間をかけて、AnimGraph のような挙動をする C++ のプログラムを作る意味があるか?と言われると、ないと思います。
あります。
理由は2つです。
1. 知らないと作業効率を高めるためのシステム設計ができない。
2. 知らないとアニメーション関連の不具合を解決できない。
シーケンサーを除くと、アニメーションに関わる機能だけでも沢山あります。
(上記ブログカードのリンク先にあるページを親として、子ページ、孫ページまで含めると100ページを超えます…。)
これ全てを覚えないと、どんなシステムを作れば作業効率を高めることができるのか?が分かりません。
アーティストやゲームデザイナーが、類似の機能が既にあることを知らずに
「こういう機能を作って欲しい。」という要望を出して来ることがあります。
要望をもらったらエンジニアが詳しく調べる必要があります。
でないと、既にある機能の劣化版を作る…という無駄なことをしてしまいます。
アニメーションがうまく動作しないときに、エンジニアに調査依頼が飛んで来ます。
アニメーションのデータに問題があるのか、アニメーションに設定したイベントに問題があるのか、AnimGraph に問題があるのか、ブループリントに問題があるのか、エンジン側のコードに問題があるのか、プロジェクト側のコードに問題があるのか、原因を突き止める必要があります。
UE のアニメーションについて、一通り把握していないと原因を突き止めることができません。
場合によっては、インポート元の FBX の中身を調べる必要が出て来るかも知れません。
バグが出た時点では、どこが悪いのか?は分からないので、エンジニア以外で調べてもらって、それでも原因を突き止められない場合は、エンジニアが詳しく調査することになります。
あらゆる可能性を考慮して、徐々に問題の箇所を絞っていく必要があります。
最終的に問題を引き起こしていたのがコードの中にあるかも知れないですし、データの中にあるかも知れません。
両方が複雑に影響し合うことで、特定のタイミングで、特定の操作をしたときだけ起きるバグかも知れません。