FPSSampleのアニメーションの実装を読む(前編)

1. はじめに

UnityのAnimatorControllerは,ステートの状態が多くなると管理しづらくなる(矢印だらけになる)という問題がある.
そこでUnity公式のサンプルではどのようにアニメーションを実装しているのか知るためソースを読んだ.

github.com

2. 前知識

まずソースを読む前に公式のドキュメントを読んでみる.
FPSSample/Animation.md at master · Unity-Technologies/FPSSample · GitHub

  • 三人称視点
    FPSSampleはマルチプレイヤーシューティングなので,アニメーションをネットワーク上で同期(複製,ロールバック,予測,ラグ処理など)するためにカスタムPlayable Graphを使用している.

  • 一人称視点
    ローカルクライアントでのみ再生されるので,AnimatorControllerを使用している. AnimatorControllerを使うとは言ったが,PlayableAPIを使わないとは言っていない(

PlayableAPIのドキュメントも読んでおく.
* Playable API - Unity マニュアル
* PlayableGraph - Unity マニュアル
* ScriptPlayable と PlayableBehaviour - Unity マニュアル
* Playable の例 - Unity マニュアル

3. 一人称視点の実装

まず簡単そうな方から読んでいく.

3.1 ファイル構成

f:id:SiunCyclone:20200601164210p:plain
f:id:SiunCyclone:20200601164608p:plain
Robot_A_1Pのコンポーネント f:id:SiunCyclone:20200601191753p:plain f:id:SiunCyclone:20200601165217p:plain

3.2 Animatorで再生される大まかな流れ

f:id:SiunCyclone:20200601200744p:plain 1. AnimGraph_AnimatorController.csAnimatorControllerの参照を持つ
2. AnimGraph_Stack.csAnimGraph_AnimatorController.csの参照を持つ
3. AnimStateController.csAnimGraph_Stack.csの参照を持つ

AnimatorはAnimationPlayableOutputのsource Playableを再生するので*1それによりアニメーションが再生されている

3.3 PlayableGraph

f:id:SiunCyclone:20200602202925p:plain ソースを読んで作った図.
この1枚にすべてが集約されている.

3.4 AnimGraph_AnimatorController.cs

  1. まずソースを簡略化してみる gist.github.com

    • RuntimeAnimatorControllerを保持している
    • AnimGraphAssetを継承している
    • 内部クラスとして,IAnimGraphInstanceを継承したInstanceがある f:id:SiunCyclone:20200601190107p:plain
  2. 親クラスとインターフェースをみる gist.github.com gist.github.com

    • InstantiateがInstatiateになっているが,おそらくUnityのAPIと被らないようにするためだと思われる
  3. 内部クラスInstanceをみる gist.github.com

    • 主な処理をCharacterAnimatorControllerに委譲していることが見て取れる
    • EntityManagerがあるので,ECSを使っている模様
  4. CharacterAnimatorControllerをみる
    コンストラクタとvoid Update()が大きい処理をしているので,その2つをみていく

    4.1 CharacterAnimatorControllerのコンストラク
    gist.github.com

    • AnimatorControllerPlayableでRuntimeAnimatorControllerをラップしてる
    • AnimatorController内のパラメータへのハッシュを,AnimStateParams型やActionStateParams型の配列として保持してる(文字列でパラメータにアクセスするよりint型のハッシュでアクセスする方が早いから)
       
      パラメータ一覧
      f:id:SiunCyclone:20200602011116p:plain
       
      4.2 CharacterAnimatorControllerのUpdate gist.github.com gist.github.com
    • AnimatorController内のパラメータを更新している

以上からCharacterAnimatorControllerのUpdateに,アニメーションがとるべき次の状態(CharacterPredictedData.LocoStateや.Action)を渡すことで,アニメーションの状態(AnimatorController内のパラメータ)を更新していることがわかった.

3.5 AnimGraph_Stack.cs

  1. 簡略化 gist.github.com

    • AnimGraph_AnimatorController.csと同じような構造
    • しかしRuntimeAnimatorControllerではなく,List<AnimGraphAsset> を保持している f:id:SiunCyclone:20200601190101p:plain
  2. 内部クラスGraphInstance gist.github.com コンストラクタで下図の部分の処理をしてる
    f:id:SiunCyclone:20200602204043p:plain

3.6 AnimStateController.cs

  1. 簡略化 gist.github.com

    • コンポーネントが非アクティブになるとDeinitialize()が呼ばれる
    • public関数が4つある
  2. public関数の中身をみる(簡略化ver) gist.github.com

    • Deinitialize()でグラフの終了処理
    • UpdatePresentationState()でグラフロジックを更新
    • ApplyPresentationState()でグラフに現在のStateを適用(多分)
  3. Initializeの中身をみる(簡略化ver) gist.github.com

    • PlayableGraphを作って再生している
    • AnimationPlayableOutputを作る時に,情報源としてAnimGraphのOutputを使っている
      Initializeで下図の部分の処理をしている
      f:id:SiunCyclone:20200602204518p:plain