今回は「アニメーションをセットアップしたのに再生されない」や「アニメーションが止まる」といった場合の対処法についてです。知っていれば「当然そうなる」(そういう設定をしている)という動作なのですが、知らないと面倒かもしれないので一覧としてメモします。
なおアニメーションをDCCツール(MayaやBlender)から出力する事それ自体に問題がある場合は含みません。
- Animation ClipのLoopが無効になっている
- リグがアニメーションを取得したFBXとモデルのFBXで一致していない
- アバターが一致しない
- 子のAnimatorを最適化している
- ステートマシンにClipが登録されていない
- AnyStateからのステート切り替えが常に成立している
- Timescaleが0
Animation ClipのLoopが無効になっている
アニメーションが途中で止まる場合、AnimationClipのLoopが外れているかもしれません。
AnimationClipは多くの場合FBX(等のファイル)から取得しますが、このアニメーションはAnimationタブの中から切り出して取得します。この時、Loopの設定が外れていると、アニメーションの完了時にアニメーション再生がポーズします。
この設定の特徴は、AnimatorControllerで見たときにステートの進行が最大値で停止しているので分かりやすいです。
一つ厄介なのが、アニメーションの停止ではなくポーズであるという事です。アニメーションは停止しますがAnimatorによるパラメーターの更新は停止しておらず、Transformの情報は毎フレーム更新され続けています。
そのため、もしUI(特にLayoutGroup)に対して使用すると、毎フレームUIが更新され続けてすごい負荷になるといった事もあります。Playable APIを使用したアニメーションの場合は再生後に正しい意味で停止するので、動作後に停止するような動きを作る場合にはSimpleAnimatorやTween系を検討するのが良さそうです。
リグがアニメーションを取得したFBXとモデルのFBXで一致していない
FBXでよくあるもう一つの設定が、リグの不一致です。
このリグは基本的にアニメーションを再生するFBXと、アニメーションを取得するFBXで一致している必要があります。HumanoidはHumanoidのアニメーションを、LegacyはLegacyのアニメーションを使用できます。
またGenericやLegacyの場合はリターゲット機能は無いので、ボーン構造も含めて一致する必要があります。
アバターが一致しない
Humanoidでデータを取得する場合に重要なのがアバターです。アバターは人形のボーン構造と実際のモデルのボーン構造を一致させる効果があります。このボーン構造が一致していないと、アニメーションは再生しません。
例えば下の場合、キャラクターはMCUnitychan
のボーン構造をしていますが、実際に適応しているのはEthanAvatar
…異なるアバターが適応されているので動かないといった具合です。
どのアバターか分からない場合、オブジェクト内のSkinnedMeshRendererを探し、Meshを生成しているFBXをたどれば見つけられます。
子のAnimatorを最適化している
少し特殊なケースですが、Animatorを階層構造にしたとき子のAnimatorが最適化していると動きません。
子の最適化を解除すれば、動作するようになります。最適化を描けたい場合は親のAnimatorで行います。
https://t.co/zdE9ZAisPE の内容で「最適化されたモデルをAnimatorの下に配置した場合」が抜けてた。そりゃそうなんだけど、知らないとハマるかもしれないケースではある pic.twitter.com/JHcyjKDmgv
— 椿 (@tsubaki_t1) 2019年3月10日
ステートマシンにClipが登録されていない
ステートマシンにクリップが登録されていない場合、当然アニメーションは再生しません。
登録したつもりでも登録してなかったり(後で差し替えるつもりだった)、GUIDの変更により剥がれる等。
AnyStateからのステート切り替えが常に成立している
AnyStateからステート切り替えが常に達成している場合、同じアニメーションが何度も再生されます。AnyStateはステートマシンを無視してステートを切り替えるので、ステート遷移条件が達成している限り現在のステート(自分自身)から自分自身のステートへ切り替えが発生してしまいます。
また遷移間隔が0の場合は見た目殆ど停止している状態になります。
対処法としては、AnyStateからの遷移から「自身に遷移」のチェックボックスを外す事です。これで少なくとも「毎フレーム自分のステートを再生し直す」事は回避出来ます。ただ、根本からの解決を考える場合は、何度もAnyStateからジャンプするステートマシンを何とかするべきでしょう。
個人的にはAnyStateには遷移条件にTriggerを必ず含めるべきと思ってます。
なおAnimator.Playは自分自身に遷移しても停止しません。3番目の引数であるNormalizeTimeまで指定すると、その時間で止まりますが。
Timescaleが0
Timescaleが0(時間の流れるスピードが0 = 時間停止 = ザ・ワールド)だと、アニメーションは再生しません。
正確にはコレは設定次第で、Animatorの設定を「スケールされていない時間」にすることで回避出来ます。
これにより「止まった時の中でも動ける」ようになりますが、同時に「加速した時間の恩恵」も受けられなくなる点に注意です。