テラシュールブログ

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

【Unity】Timelineのアニメーションに微調整を加える(Humanoid編)

前回に引き続き、Timelineのアニメーションに微調整を加える方法です。

今回はHumanoid向け

HumanoidはTimelineでアニメーションを上書きしにくい

Humanoid Rigで動く部位の場合、Genericと同じ方法でアニメーションの微調整が出来ません。というのも、Timelineから生成するアニメーションは基本的にGenericになるので、Humanoidとは互換性がない為です。

(つまり髪や手首といった

なので、Humanoidのアニメーションを微調整したい場合、IK を使用するか、Constraint で少し動作に追加エフェクトをかける必要があります。

f:id:tsubaki_t1:20190523223841j:plain

IKを使用する場合

IKを使用する場合、AnimatorのIKを使用して手や足の位置を調整します。

IKの設定は普通に行います。例えば下のようなコンポーネントをIKを使用するAnimatorに設定します。

using UnityEngine;

[RequireComponent(typeof(Animator))]
public class CharacterIK : MonoBehaviour
{
    [SerializeField] AvatarIKGoal goal;  // どの部位のIKを使用するか
    [SerializeField] AvatarIKHint hint;  // goalと同じ部位のヒントを選択
    [SerializeField] Transform goalTransform;// 最終的な位置
    [SerializeField] Transform hintTransform;// 肘や膝の位置のヒント

    [SerializeField][Range(0, 1)] float weight, hintWeight;

    private Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
    }

    private void OnAnimatorIK(int layerIndex)
    {
        animator.SetIKPosition(goal, goalTransform.position);
        animator.SetIKHintPosition(hint, hintTransform.position);

        animator.SetIKHintPositionWeight(hint, hintWeight);
        animator.SetIKPositionWeight(goal, weight);
    }
}

f:id:tsubaki_t1:20190523224340j:plain

あとはIKを動かせるようにする訳ですが、ここでのポイントがAnimatorControllerでIKを有効化する事です。Timelineで動かす場合もIKの設定は有効になるみたいです。

もし対象がカットシーン専用データ(AnimatorControllerを持っていない)場合は、空のAnimatorController(AnimationClipが一切登録されていない)でもOKみたいです。

f:id:tsubaki_t1:20190523224554j:plain

これでTimeline中でも視点や手の位置といった部位は調整出来ました。

個人的にはTimelineの仕組みを考えるとバグな気もしますが、動きます。

Constraintを使用する場合

IKが使用できないケース…例えば腕の向きを僅かに変更したい…つまりFK的なアプローチが必要な場合は、こちらで行います。

これは正直なところ、コードのLateUpdateで更新する方が理にかなっているような気もしますが、面倒くさいのでConstraintで云々してしまいます。例えば足を少し調整したい場合

  • Rotation Constraint を足のボーンに追加
  • Rotation Constraintに足のボーンとエフェクターを設定
  • 有効な方のウェイトを1にして、他を0にする

という感じで行けます。

f:id:tsubaki_t1:20190523230029j:plain

関連

今回のIKのアプローチを使用してボーンを動かすプロダクトです。

github.com

【Unity】Timelineのアニメーションに微調整を加える(Generic編)

DCCからアニメーションをUnityに持ってきてから、Timeline上のアニメーションを微調整したいといったケースがあります。例えばドラゴンが噛み付く位置が少しズレているだとか、棍棒を叩きつける位置が微妙に違う等。特にオブジェクトの配置をゲーム上で行っている場合、DCCツールとUnityエディターを行き来するのは少し面倒そうです。

ということでTimeline上で微調整してみます。なお、今回はGeneric用のアプローチについてで、Humanoid用は次回です。

1. Timeline上でアニメーションを再生する

まず最初にGenericなモデルをタイムライン上でアニメーションしている状態です。普通にアイドルモーションしています。

この状態はボーンの位置がTimelineのAnimationClipで決められているので、首を動かしたり少しズラしたりすることは出来ません。

f:id:tsubaki_t1:20190508223205g:plain
ドラゴンのアイドルモーション

2. モーションを編集しやすくする

ボーン構造を少しズラします。ただAnimationClipを編集するのは正直行いたくないので、FKベースでアニメーションの動きを少しオーバーライドします。
この最初の手順は、リグを視覚的に見やすくします。

Aniamtion RiggingBone Rendererコンポーネントを使用して、ボーン構造をSceneView上に表示します。

メッシュのボーン構造(動かすとモデルが変形する、OptimizedGameObjectで非表示になるGameObject)をBoneRendererのTransformsにドラッグ&ドロップすれば、ボーン構造が視覚的に確認出来るようになります。また、ボーン構造それ自体を選択しやすくなり、編集しやすくなります。

f:id:tsubaki_t1:20190508223918j:plain

f:id:tsubaki_t1:20190508224040g:plain

3. アニメーションをオーバーライドする

Timeline上のアニメーションをオーバーライドします。

  1. AnimationTrackを右クリックしてAdd Override Trackを選択
  2. レコードボタンを押してレコード開始
  3. 動かしたいタイミングでキーフレームを登録

f:id:tsubaki_t1:20190508224552g:plain

これでTimeline上でアニメーションを少し編集出来ますが、少し問題があります。

4. オーバーライドしたアニメーションの範囲を限定する

上の手順でアニメーションを編集した場合、編集した内容が最初から最後まで反映されっぱなしになります。特定の瞬間だけ上書きしたいので、これは望ましくありません。

なのでアニメーションの範囲を限定し、ついでにオーバーライドするアニメーションが既存のアニメーションに自然につながるようにします。

  1. AnimationTrackでConvert to clip trackを選択
  2. 変換したAnimationClipを選択
  3. Ease in durationEase out durationに0以外を設定

f:id:tsubaki_t1:20190508225315g:plain

これでGenericなキャラクターの動きを微調整出来ます。

感想

実際には完全オーバーライドよりお「+N°回す」的な方が多いかもしれません。そういったものはLateUpdateで補正するなり、色々と。

なおこのアプローチの本質は「Genericモーションを作って上書き」なので、Humanoidの場合は別のアプローチが必要になります。それは次回。

関連

今回使用したモデル

assetstore.unity.com

【Unity】Animation Rigging、人型以外のキャラクターにもIKを!

f:id:tsubaki_t1:20190120234723j:plain

今回はUnity 2019.1のPackageManagerで使えるようになるAnimation Riggingについてです。

Animation Rigging

AnimationRiggingは、Animation C# Jobsの上でキャラクターを手続き的に動かす機能みたいです。例えばIKをセットアップしたり、動きを調整したり。

それ以外でもTimelineで動くキャラクター(Humanoid)の腰に回転を加えてみるなど、特定のシーンでの微調整といった意味では中々に面白い機能です。

f:id:tsubaki_t1:20190120234137g:plain
キャラクターの腰の動きをオーバーライドする

IKで言えばAnimator(Mecanim)に標準で付いているじゃん!という考えもありますが、MecanimのIKはHumanoid限定なのに対して、AnimationRiggingはGenericなRigを持つキャラクターでもIKを利用出来ます。正確にはIKを実装すれば使えるというのが正しく、最初から付いてるのはTwoBoneIKだけです。(サンプルだとフルボディIKがあったんだけど…)

例えば下のキャラクター(明らかに人型ではない)の足の動きはIKで作成しています。足の最終的な位置だけを示して、後はIKの機能で調整していると言った感じです。

f:id:tsubaki_t1:20190120234505g:plain
足をIKで動かす

他にもアニメーションで動くキャラクターのTransformのオーバーライドや、複数の動きのブレンドなど色々と出来るみたいです。

  • Blend Constraint
  • Chain IK Constraint
  • Damped Transform
  • Multi-Aim Constraint
  • Multi-Parent Constraint
  • Multi-Position Constraint
  • Multi-Referential Constraint
  • Multi-Rotation Constraint
  • Override Transform
  • Twist Correction
  • Two Bone IK Constraint

実際に使ってみる

実際にコレを使ってみます。今回試す機能はTwoBoneIKです。2つの関節でIK表現を行います。

アームの先端を動かすと、先端につながるようにアームの位置が補完されています。

f:id:tsubaki_t1:20190507224513g:plain
TwoBoneIKでアーム

試した環境

  • .NET 4.x
  • Unity 2019.1
  • Animation Rigging ver 0.1.4

手順

まずアームを作ります。

最も親となるGameObject「ARM」の下に、Root > Mid > Tipになるように親子構造を構築します。この時、親となるGameObjectを回すと綺麗に子のボーンが回るようにメッシュの位置を調整しておきます。

f:id:tsubaki_t1:20190507225303j:plain
親子構造でアームを作る

f:id:tsubaki_t1:20190507225722g:plain
FKで動かせる事の確認

次にRigを設定します。

ARMの下にRigというGameObjectを作成し、RigコンポーネントTwoBoneIKConstraintコンポーネントを追加します。

Rigオブジェクトの下にTargetとHintというGameObjectを生成し、TwoBoneIKConstraintに登録していきます。この時TargetはTipと大体同じ位置に配置しておくが吉です。

f:id:tsubaki_t1:20190507230439j:plain

あとはRigBuilderを作成し、先ほど作成したRigオブジェクトを登録します。これでゲーム実行時にTwoBoneIKが動作します。

f:id:tsubaki_t1:20190507231532j:plain

動画でみたい場合、下の動画が分かりやすいです。

www.youtube.com

また導入の際、パッケージからサンプルが導入出来ます。中に色々とサンプルが入っているので追ってみるのも面白そうです。

f:id:tsubaki_t1:20190507231042j:plain

【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
時間が流れる速度を無視して、常に一定速度で動く