テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】「アニメーションが再生されない」「止まる」時の対処法

今回は「アニメーションをセットアップしたのに再生されない」や「アニメーションが止まる」といった場合の対処法についてです。知っていれば「当然そうなる」(そういう設定をしている)という動作なのですが、知らないと面倒かもしれないので一覧としてメモします。

なおアニメーションをDCCツール(MayaやBlender)から出力する事それ自体に問題がある場合は含みません。

Animation ClipのLoopが無効になっている

アニメーションが途中で止まる場合、AnimationClipのLoopが外れているかもしれません。

AnimationClipは多くの場合FBX(等のファイル)から取得しますが、このアニメーションはAnimationタブの中から切り出して取得します。この時、Loopの設定が外れていると、アニメーションの完了時にアニメーション再生がポーズします。

この設定の特徴は、AnimatorControllerで見たときにステートの進行が最大値で停止しているので分かりやすいです。

f:id:tsubaki_t1:20190111202502j:plain
アニメーションのループ

f:id:tsubaki_t1:20190111202611j:plain
ステートの再生が最大で停止する

一つ厄介なのが、アニメーションの停止ではなくポーズであるという事です。アニメーションは停止しますがAnimatorによるパラメーターの更新は停止しておらず、Transformの情報は毎フレーム更新され続けています。

そのため、もしUI(特にLayoutGroup)に対して使用すると、毎フレームUIが更新され続けてすごい負荷になるといった事もあります。Playable APIを使用したアニメーションの場合は再生後に正しい意味で停止するので、動作後に停止するような動きを作る場合にはSimpleAnimatorやTween系を検討するのが良さそうです。

リグがアニメーションを取得したFBXとモデルのFBXで一致していない

FBXでよくあるもう一つの設定が、リグの不一致です。

このリグは基本的にアニメーションを再生するFBXと、アニメーションを取得するFBXで一致している必要があります。HumanoidはHumanoidのアニメーションを、LegacyはLegacyのアニメーションを使用できます。

f:id:tsubaki_t1:20190111203901j:plain
リグの設定一覧

またGenericやLegacyの場合はリターゲット機能は無いので、ボーン構造も含めて一致する必要があります。

アバターが一致しない

Humanoidでデータを取得する場合に重要なのがアバターです。アバターは人形のボーン構造と実際のモデルのボーン構造を一致させる効果があります。このボーン構造が一致していないと、アニメーションは再生しません。

例えば下の場合、キャラクターはMCUnitychanのボーン構造をしていますが、実際に適応しているのはEthanAvatar…異なるアバターが適応されているので動かないといった具合です。

f:id:tsubaki_t1:20190111205158j:plain
モデル本来のアバター

f:id:tsubaki_t1:20190111205101j:plain
モデルのアバターではないアバターを設定

どのアバターか分からない場合、オブジェクト内のSkinnedMeshRendererを探し、Meshを生成しているFBXをたどれば見つけられます。

f:id:tsubaki_t1:20190111205632g:plain
アバターを探せ

子のAnimatorを最適化している

少し特殊なケースですが、Animatorを階層構造にしたとき子のAnimatorが最適化していると動きません。

子の最適化を解除すれば、動作するようになります。最適化を描けたい場合は親のAnimatorで行います。

ステートマシンにClipが登録されていない

ステートマシンにクリップが登録されていない場合、当然アニメーションは再生しません。

登録したつもりでも登録してなかったり(後で差し替えるつもりだった)、GUIDの変更により剥がれる等。

f:id:tsubaki_t1:20190304125827j:plain
クリップが「無し」

AnyStateからのステート切り替えが常に成立している

AnyStateからステート切り替えが常に達成している場合、同じアニメーションが何度も再生されます。AnyStateはステートマシンを無視してステートを切り替えるので、ステート遷移条件が達成している限り現在のステート(自分自身)から自分自身のステートへ切り替えが発生してしまいます。

f:id:tsubaki_t1:20190304125037j:plain
AnyStateは他のステートからアニメーションを切り替える

また遷移間隔が0の場合は見た目殆ど停止している状態になります。

f:id:tsubaki_t1:20190304124946j:plain
遷移間隔が0 = アニメーション遷移終了後に即座に他のステートに移れる

対処法としては、AnyStateからの遷移から「自身に遷移」のチェックボックスを外す事です。これで少なくとも「毎フレーム自分のステートを再生し直す」事は回避出来ます。ただ、根本からの解決を考える場合は、何度もAnyStateからジャンプするステートマシンを何とかするべきでしょう。

個人的にはAnyStateには遷移条件にTriggerを必ず含めるべきと思ってます。

f:id:tsubaki_t1:20190304125328j:plain

なおAnimator.Playは自分自身に遷移しても停止しません。3番目の引数であるNormalizeTimeまで指定すると、その時間で止まりますが。

Timescaleが0

Timescaleが0(時間の流れるスピードが0 = 時間停止 = ザ・ワールド)だと、アニメーションは再生しません。

正確にはコレは設定次第で、Animatorの設定を「スケールされていない時間」にすることで回避出来ます。

f:id:tsubaki_t1:20190304123920j:plain

これにより「止まった時の中でも動ける」ようになりますが、同時に「加速した時間の恩恵」も受けられなくなる点に注意です。

f:id:tsubaki_t1:20190304124008g:plain
時間が流れる速度を無視して、常に一定速度で動く