UnityのTimelineをいくらか理解する

2018年06月18日

(2021年1月8日)PlayableGraph VisualizerをPackage Managerでインストール
(2020年6月27日)リンクをいくらか修正


Timelineは、マルチトラックでアニメーションクリップや音声などを再生できるUnityの新機能です。ゲームのカットシーンや、映像シーケンスを作るのに用いるのですが、謎めいたところが多いです。しばらく雰囲気で使っていたのですが、気持ち悪い感じが抜けなかったので、もう少し全体像を把握できないものかと思って調べてみました。

普通にTimelineを使うサンプル

まず、Timelineの標準的なサンプルとしては以下の2つがあります。アセットが多く凝っているのですが、Timeline1本に、ほとんどがActivation Track(ゲームオブジェクトの有効・無効を切り替えるトラック)と、Animation Track(ゲームオブジェクトをアニメーションさせるトラック)で動いています。とりあえずTimelineで映像を作る方法を知りたい、標準的な作法を知りたいということでしたら、この2つのプロジェクトファイルを開いてみるのが最速でしょう。

ただもっとプログラム的なあれこれ、たとえばTimelineからスクリプトを呼び出したりしようとすると、これどうすればいいの? そもそもTimelineの内部構造どうなってるの? とわけわからん状態になりがちです(というかなりました)。そのあたりを探ってみることにしましょう。

とりあえずTimelineを使う

このエントリではTimelineの使い方の詳細には触れないのですが、説明のために簡単にTimelineを使う方法を書いておきます(もう使い方を知っている場合は飛ばして構いません)。

Unityの新規プロジェクトを作成して、Projectウィンドウで Create > Timeline でTimelineアセットが作成されます。TimelineアセットをHierarchyウィンドウにドロップすると、Playable Directorコンポーネントがアタッチされたゲームオブジェクトが作成されます。

Playable DirectorコンポーネントのTimelineAssetのダブルクリックするとTimelineエディターウィンドウが開きます。Timelineエディターウィンドウの左上にある Add ボタンでトラックを作成できますので、たとえばAnimation Trackを作成します。シーン上に何か適当なオブジェクトを作成してAnimation Trackにドロップすると、Timeline用のAnimatorコンポーネントがアタッチされます。トラックの赤丸をクリックすると「Recording…」表示になりますので、白い再生ヘッドとオブジェクトを動かすとキーフレームが記録されます。

エディターを再生すると、Playable Directorコンポーネントの「Play On Awake」によりタイムラインが再生されます。

Timelineエディターウィンドウの詳細についてはマニュアルを参照してください。

Playable Directorという謎コンポーネント

さて、この時点で謎めいたところが出てきます。Playable Directorって何?

Playable DirectorコンポーネントのPlayableプロパティにTimelineアセットを割り当てて、Bindingsでシーン上のオブジェクトとバインドされタイムラインが再生されるのですが、Playableプロパティの型はPlayableAssetになっています。TimelineAssetはPlayableAssetの継承クラスですので、Timeline以外も扱えそうな雰囲気です。が、ドキュメントを見てもTimelineのことしか書いていません。

Playable Director コンポーネントは、タイムラインインスタンスとタイムラインアセットの間のリンクを格納します。Playable Director コンポーネントは、いつタイムラインインスタンスを再生するか、どのようにタイムラインインスタンスがその時計を更新するか、および、タイムラインインスタンスが再生を終了したとき何を発生させるかを制御します。

現状はTimeline専用のコンポーネントであり、実質「Timeline Player」のようなものだと理解してしまって差し支えなさそうです。

が、どうやらTimelineはPlayableというものを基礎にしているようです。ちょっとPlayableのほうを把握したほうがよさそうです。

Playable APIについて

Playableについてはドキュメントのここから下を見るのがいいでしょう。

Playable APIは、アニメーションクリップ等の「再生できるもの(Playable)」をノードとして繋げて出力する汎用的な仕組みです。Playableという名前が抽象的な上に、以下のようにPlayableなんとかというクラスがぞろぞろ登場してこれまた分かりにくいです。

  • Playable
  • PlayableBehaviour
  • PlayableDirector
  • PlayableGraph
  • PlayableOutput

ざっくりと説明すると、Playable(というノード)を連結してPlayableGraphが構築されます。ノードは最終的にPlayableOutputに接続され出力されます。Playableを継承するAnimationClipPlayableや、PlayableOutputを継承するAnimationPlayableOutput等のクラスがあり、これらを使ってアニメーションクリップを再生したりできます。テラシュールブログさんが参考になります。

また、スクリプトで動作を記述できるカスタムPlayableというものがあり、PlayableBehaviourの継承クラスで振る舞いを記述してScriptPlayableでカプセル化することで作成できます。

PlayableDirectorは先の通りTimelineを再生するためのコンポーネントです。

TimelineのPlayable Graphを見てみる

Playableのノードの繋がりを可視化してくれるPlayableGraph VisualizerというパッケージがUnity公式から提供されています。こちらでTimelineを見てみましょう。

Package Managerの左上の+ボタンから Add package from git URL… を開いて com.unity.playablegraph-visualizer を入力するとパッケージがインストールされます。

HierarchyのPlayable Directorコンポーネントがアタッチされているオブジェクトを選択して、Window > PlayableGraph Visualizer を開くと、Timelineが再生するPlayable Graphが構築された状態が表示されます。下記は一例で、Timelineを操作・再生するとリアルタイムでノードの表示も変化します。

PlayableGraph Visualizerでは、各ノードの「Playable」という文字列は(長いので)省略されて表示される仕様になっています。たとえば上のグラフなら、右端のAnimationClipPlayableから、左のTimelinePlayable、AnimationPlayableOutputまで繋がって出力されています(省略される「Playable」文字列の位置が違うのでややこしい)。

上のグラフでは(画像が小さくて見えませんが)「Animation Motion X To Delta」という得体の知れないノードも表示されています。これはAPIリファレンスに載っていないAnimationMotionXToDeltaPlayableで、UnityCsReferenceで見れたりします(追記:現在このクラスはなくなってる?)。

さて、何のためにこうしたPlayableのグラフが構築されるのかといいますと、たとえばクリップのミックスです。

Animation Trackを作って3つのアニメーションクリップを置いたとします。Timeline上のアニメーションクリップは範囲を重ねてブレンドすることができます。このときPlayable Graphは下のようになります。

トラック上に置かれた3つのクリップが右端にあるAnimationClip(Playable)に対応します。これが水色のAnimationMixer(Playable)でミックスされます。再生マーカーが1つ目と2つ目のアニメーションクリップの中間にあるので、この2つのウェイトが上がり、AnimationClipPlayableからより白い線が出ています。

アニメーションに限りません。TimelineのクリップはすべてPlayableであり、それをトラック上でブレンドして出力するのにPlayable APIという汎用的な再生の仕組みを用いているわけです。これがTimelineとはある種独立した仕組みを用いているので分かりにくかったのですね。

ところで、PlayableGraph Visualizerですが、Timelineのトラックを増やしていくと下のようななかなかアグレッシブな表示になります。TimelinePlayableから複数のPlayableOutputに出力されるのに対応してないため、何重にも並んで表示されてしまうとのことです。対応予定だそうですが、今のところは、実際のプロジェクトというよりも、シンプルなTimelineでどんなPlayable Graphが構築されるか確認・理解するのに使うのがいいでしょう。

というところまで踏まえた上で、Timelineでスクリプト拡張する方法を見てみましょう。まずPlayableを触らない方法から。

スクリプト拡張:Playable触りたくないコース

Activation Trackで制御する

Activation Trackに適当なオブジェクトを割り当てて、そのオブジェクトのOnEnable、OnDisableでスクリプトを実行するというテクニックがあります。UnityのTimelineの中の人も使っている由緒正しい方法です。

Control TrackでITimeControlを使う

MonoBehaviourとITimeControlを継承したクラスを作ると、スクリプトでクリップ内の時刻を取得できます。クリップの時刻のみをベースに何かを動かすときはこの方法が簡単です。

Control Trackを作成してAdd Control Playable Asset Clipでクリップを追加、Source Objectにゲームオブジェクトを登録します。

Animation Trackでプロパティを書き換える

Animation Trackでオブジェクトのプロパティを書き換え、それをもとにスクリプト制御したりできます。たとえば直接アニメーションできないQualitySettings等を操作するのに有用です。

スクリプト拡張:Playable触ってもいいよコース

Playable Trackを使う

TimleineのPlayable TrackでカスタムPlayable(PlayableBehaviourで振る舞いを記述したScriptPlayable)を再生できます。

Projectウィンドウで Create > Playables > Playable Behaviour C# Script / Playable Asset C# Script を実行するとPlayable Trackで使用する2つのスクリプトの雛形ができます。PlayableBehaviourの雛形クラスで動作を定義して、PlayableAssetの雛形クラスのCreatePlayableでPlayableBehaviourを使用したScriptPlayableを生成するように書き換えます。例を2つ示します。

クリップにstringプロパティを追加するには

PlayableAssetのテンプレートを生成したばかりの状態ではPlayable.Createしているのを、PlayableBehaviourからScriptPlayableを生成するように変更します。

	public string message
	...
        var behaviour = new CharacterVoiceBehaviour();
        behaviour.message = message;
        return ScriptPlayable<CharacterVoiceBehaviour>.Create(graph, behaviour);

PlayableBehaviorのテンプレートには

	public string message

を追加すると、OnBehaviourPlay等でクリップのmessageが代入されています。

クリップに参照プロパティを追加するには

PlayableAssetのテンプレートに

	public ExposedReference<GameObject> testObject;
	...
        var behaviour = new CharacterVoiceBehaviour();
        behaviour.testObject = testObject.Resolve(graph.GetResolver());
        return ScriptPlayable<CharacterVoiceBehaviour>.Create(graph, behaviour);

PlayableBehaviourのテンプレートに

	public GameObject testObject

を追加すると、OnBehaviourPlayでtestObjectが代入されています。

ちょっと説明手抜きです。こちらのページが参考になります。

Default Playablesでカスタムトラックを作る

最後に紹介するこれはある意味フルスペックな方法です。

Unity公式からDefault Playablesというアセットが提供されています。これをインポートすると、ウィザードでTimelineのカスタムトラックのテンプレートスクリプトを作成できます。また、いくつかのカスタムトラックのサンプルが入っています。個人的にはこのアセット名前が悪すぎると思っていて、Timeline Custom Track Generator & Examplesのようなものと考えたほうがすんなり使えると思います。

インポートして、Windows > Timeline Playable Wizard… でテンプレートスクリプト一式を生成するウィザードが開きます。ウィザードは大まかにStandard Blend Playableがオンとオフのモードがあります。

Standard Blend Playableをオンにする場合の例としては、以下のようにして「Create」ボタンを押すと、TimelineエディターウィンドウのAddメニューからTransformをバインドできるトラックが作れるようになり、クリップにTransformのpositionを設定してブレンドできるようになります。

一方、Standard Blend Playableをオフにして以下のようにすると、バインドオブジェクトなしで、各クリップに文字列を格納するトラックが作れるようになります。

Standard Blend Playableオフで生成したカスタムトラックはそのままでは何もしませんので、動作を記述する必要があります。カスタムトラックの動作の書き換えは主にMixerBehaviourで行います。MixerBehaviourでトラックのすべてのクリップのPlayableBehaviourとウェイトが取得できますので、それをもとに処理を行います。たとえばこの場合、生成されたDialogueMixerBehaviour.csで

// Use the above variables to process each frame of this playable.
if (inputWeight == 1f)
{
    Debug.Log(input.message);
}

とすると、再生マーカーがクリップの範囲に入ったときにクリップのmessageの内容がコンソールに出力されます。

ウィザードでは以下のような5つ(4+1つ)のスクリプトが生成されます。なんで5つもあるんだと思うかもしれませんが、TimelineがPlayableをベースにしていることや、個々のスクリプトの役割を把握したあとだと妥当だと感じるのではないでしょうか(……え、そうでもない?)。

*Track.cs

トラックにバインドされるオブジェクトやクリップの型、トラックの色等が定義できます。

*MixerBehaviour.cs

トラック上のすべてのクリップをミックスするPlayableです。トラックの振る舞いを定義するには、基本的にはこのスクリプトを書き換えます。

*Clip.cs

PlayableAsset、ITimelineClipAssetを継承します。ITimeilneClipAssetはClipCapsを定義します。

*Behaviour.cs

PlayableBehaviourを継承します。クリップのパラメータを保持するだけで基本的にはほぼ何もしません。

Editor/*Drawer.cs

Standard Blend Playableがオフのときに「Create Drawer?」をチェックすると生成されるエディタ拡張スクリプトです(基本的にはオンにします)。クリップのインスペクタの表示を簡潔にします。

Default Playablesアセットに同梱されているサンプルを参照すると、カスタムトラックの動作をどう記述すればいいかのヒントになるかもしれません。また、Unite 2018 Tokyoの下記講演・スライドも参考になります。

最後にTimelineのTipsあれこれです。

Tips

Cinemachineのカメラを制御したい

CinemachineをインポートするとCinemachine Trackが作れるようになります。Cinemachine TrackにCinemachine Brainのアタッチされたカメラを設定、トラックで右クリックしてAdd Cinemachine Shot Clipでバーチャルカメラを割り当てます。クリップをブレンドするとカメラの位置がブレンドされたりします。

Timelineの再生終了を検知するには

PlayableDirector.stoppedイベントが使用できます。Unity 2017以前ではPlayableDirector.stateの変化を監視とかでしょうか。

Timelineをマニュアル再生するには

PlayableDirector.timeUpdateModeをManualにします。PlayableDirectorのtimeで再生位置を更新してEvaluateしてください。Playする必要はありません。

なお、Evaluateで位置更新するとAudio Trackの音が鳴りません。カスタムTrackを作るなどして自分で鳴らす必要があります。

プレビューでAudio Trackの音が鳴らない

Unity 2018.2から鳴ります。Timelineエディターウィンドウの右上メニューにEnable Audio Scrubbingというのが追加されていて、有効にするとスクラブ再生もできますが、みんなが想像する鳴り方と違うような……。

Timelineの中で他のTimelineを再生するには

Control Trackを作成して、他のPlayable Directorを持つゲームオブジェクトをドロップしてください。Unity 2018.2では、クリップをダブルクリックするとサブTimelineを開くことができます。

なお、メインのTimelineのUpdate MethodをManualにする場合は、呼び出されるTimelineのUpdate MethodもManualにする必要があります。

Timelineからイベントをシンプルに呼び出したりできないの?

Timelineイベントというのがあったそうですが、リリースされる直前に問題があってなくなったそうです。Unity 2018.2か2018.3で復活見込みとのことです。

Before Timeline released, we had an internal version with Timeline Events. It was mostly working, but we had problems with UI and timing (in some cases events were triggered when they should not have been). We cut that feature right before release because it wasn’t at a quality level we judged appropriate. We really wanted that feature though, so expect to see it return in the future (although I can’t provide a time frame).

we are targeting early-mid 2018 for a timeline event system. they will land in 2018.2 or 2018.3.

Timelineの再生速度を変更するには

Timeline再生時にPlayable Graphが構築されているのでそこからいろいろ制御できます。例えば以下のようにします。

playableDirector.playableGraph.GetRootPlayable(0).SetSpeed(speed)

Audio Trackで音を鳴らすとクラッシュ

Unity 2017.4.4f1でAudio Trackでサウンドを鳴らすとアプリケーション終了時にクラッシュするのをいくつかのプロジェクトファイルで経験しています。OnApplicationQuitでPlayable Directorを停止して回避しました。Unity 2018で直っていそうな気もしますが未確認です。

Timelineのベストプラクティス

可能な限り、ビルドしたりエディタを再生したりせず、Timelineエディターウィンドウを開いてスクラブするだけで動作をある程度確認できるようにしておくとイテレーションが速くなるのでおすすめです。あとよく忘れるのですが、Timelineウィンドウの右上のボタンでウィンドウの表示をロックできます。

Timeline総評

Playable APIを基盤にしていたり、全体的に名前が良くなかったりで分かりにくいところはありますが、ざっくりやりたいことは分かるし素直に使っていきたいなという感じです。個人的には標準機能大好きですしね(UNetとか(略))。お仕事(ハシラス)のVRコンテンツでは、Timelineで素直にアニメーションを再生しつつ、インタラクティブなオブジェクトのみを別制御したり、ネットワーク同期したりということをやっています。

(書いた人: こりん

ブログトップへ