
Unity2017のTimelineをやってみた
こんにちは。Unityエンジニアの新井です。
今回はUnity2017で導入が予定されている新機能Timeline(beta版)を動かしてみたいと思います。 Timelineについての記事はすでにいくつか見かけますが、導入方法やコンポーネントの名称などがbetaのバージョンによって大きく違っている箇所もあったので、最新のUnity2017.1.0b9(6/10現在)を使って改めて検証したいと思います。
Timelineとは?
一言でいうと、時系列にAnimationClipやAudioClip、Cameraを配置することができ、シーケンシャルにアニメーションを実行するエディタウィンドウです。 例えば、何かのアニメーションを終えて別のキャラクターアニメーションを発動し、そのアニメーションの途中のとあるタイミングでカメラの動きを変更し、カメラの動きのこのあたりでエフェクト出して…(続く)といったタイミングを考慮したカットシーンを作りたい時、Timeline上に置かれたクリップをドラッグしてずらなどして、再生タイミングや再生時間を調整することが簡単にできます。 また、配置したオブジェクトを動かして、かつ、その場でRecordingしてAnimationClip化することも可能です。

Recordingボタン
AnimatorControllerとの違い
UnityにはAnimatorControllerという仕組みが用意されています。個々のオブジェクト(GameObject, Camera, UIなど)のアニメーションステートを管理する場合には有効ですが、複数のAnimatorControllerを全体の時間軸に沿うように扱う事はできず、一つのAnimationClipに個々のオブジェクトを取り込んでキーフレーム制御する必要がありました。 その方法でもやりたいことが実現出来なくはないですが、凝ったシーンを作ろうとした場合、構造が複雑になり修正や追加開発に時間がかかったりAnimationEventが入っている場合など仕様が漏れがちで、イベントトリガーを進行管理に使っていた場合には大きなバグを引き起こす危険性も考えられます。

Animation State
Timelineエディタの導入で、直感的なGUI操作でプログラマを介することなく制御したい複数のオブジェクトの表示タイミングや時間などを調整することが容易でシンプルになり、クリエイティブのイテレーション回数を増やす事が可能になったと思っています。
Timelineにできること
- Timeline上でGameObject、カメラ、オーディオを制御できる
- 時系列に並べて、再生・表示タイミングと期間をGUIベースで制御できる
- Timelineで指定した期間断続的に発動するスクリプトを制御できる
導入方法
Assets > Create > Timeline か、または、Projectウィンドウ上で右クリックやCreateボタンからも追加できます。
「New Timeline」というオブジェクトがProjectウィンドウに追加されます。

Timeline Asset
Projectウィンドウに追加された Timelineオブジェクト(New Timeline)をヒエラルキーにドラッグ&ドロップします。
(サンプルでは名前を”Timeline”にしています)
ヒエラルキーにドラッグ&ドロップしたTimelineオブジェクトを選択するとPlayableDirectorがAddComponentされていて、「Playable」ボックスに作成したNew Timelineがアタッチされている事が確認できます。

PlayableDirector
次に、編集用のエディタウィンドウを表示します。
Window > TimelineEditorよりTimelineWindowを選択します。Timelineに配置したClipはドラッグすることで表示時間を変更できます。

Clipはドラッグできる
メモ Timelineウィンドウは、他のオブジェクトを選択するたびに表示が途切れますので、ロックをかけておくことをおすすめします。 また、「Preview」が押されていない場合は、Trackにオブジェクトを紐付けることができません。Previewが押せない場合は、 一度noneを選択して、再度指定のTimelineを選ぶと押せるようになります。

Previewが押せない件
Trackの追加
Timelineを利用するには各種オブジェクト(GameObjectやCameraなど)を「Track」と呼ばれるAssetにバインドする必要があります。
Trackには用途別にいくつかの種類があり、AddボタンからTimelineに追加することで利用可能です。

Trackの追加
Track Group
各Trackをグループ化します。
Activation Track
設定したGameObjectの表示、非表示をおこないます。
Timeline上で右クリック > AddActivationClip をしてTimelineに追加したClipの長さ(時間)だけバインドしたオブジェクトをActiveにします。

Activation Track
Animation Track
AnimationClipを使用することが出来ます。既存のAnimationClipを追加したり、Timeline上で直接アニメーションカーブを付けることで、新規のAnimationClipとして保存することが出来ます。(Recording機能)
また、Clipのつなぎをクロスフェードさせることも可能です。

Animation Track
Audio Track
AudioClipを制御するために利用します。

Audio Track
Control Track
prefabをインスタンス化することが出来ます。インスタンス化するprefabと親のGameObjectを指定出来ます。
パーティクルの表示はこの機能を使うと良さそうです。

Control Track
Playable Track
スクリプトを扱う事が出来ますが使い方はやや特殊で、あとでもう少し踏み込んで検証します。

Playable Track
Cinemachine.Timeline
カメラを扱うTrackになります。(後述)
サンプルをつくってみる
GameObject(サンプルはユニティちゃん)が動き、それをカメラが追うという簡単なサンプルを作ってみます。

走るユニティちゃん
Track作成の流れ
- 動かしたいオブジェクトの設定(AnimationTrack)
- タイムライン進捗で移動するようなスクリプトを準備(PlayableTrack)
- 動かしたいカメラをAnimationTrackに設定(AnimationTrack)
Trackの追加とバインド
新しいシーンを作り、これまでの手順でTimelineをヒエラルキーに追加します。
Timelineウィンドウを開いてロックを掛け、AddボタンからAnimationTrackを追加し、動かしたいGameObject(ユニティちゃん)をバインドします。
AnimationTrackのTimeline上で右クリック>Add From Animationを選択し、再生したいAnimationClipを選択。(標準のRunning@loopを選択)

Add AnimationClip
Playable Trackの導入
次にGameObjectの移動についてですが、いろいろな方法が考えられます。せっかくなので、Timelineのシークバーの移動にあわせて進む(あるいは戻る)ようにしたいと思います。
シークバーの移動で処理を加えるにはTimelineに関するAssetをスクリプトで制御する必要があり、Playable Trackで利用することができます。
また、PlayableTrackを使用するために、あらかじめ、以下2つのPlayableスクリプトを用意しておく必要があります。
PlayableAsset
Timelineのトラック上に配置し、設定した項目をScriptPlayableのCreateを使用しPlayableBehaviourに渡すスクリプト
PlayableBehaviour
TimelineのPlayableTrackにアタッチされたPlayabaleAssetの振る舞いが書かれたスクリプト。
Assets > Create > Playables より作成します。
ここでは名前をそれぞれTimelinePlayableAsset、TimelinePlayableBehaviourにしました。

Playableスクリプトの作成
TimelinePlayableAsset.cs(コード全文)
using UnityEngine; using UnityEngine.Playables; [System.Serializable] public class TimelinePlayableAsset : PlayableAsset { public ExposedReference charaObj; // Factory method that generates a playable based on this asset public override Playable CreatePlayable(PlayableGraph graph, GameObject go) { var behaviour = new TimelinePlayableBehaviour(); behaviour.charaObject = charaObj.Resolve(graph.GetResolver()); return ScriptPlayable.Create(graph, behaviour); } }
コードの説明
動かしたいGameObjectは”charaObject”をいう名前であらかじめアタッチしていますが、
TimelineAssetで使用する場合、アタッチ方法が新しい方法になります。
public ExposedReference charaObject;
ExposedReferenceは5.6から追加されたものです。PlayableAssetはアセットであるため、シーンの特定オブジェクトをEdit中(再生していない時)に参照することができません。ExposedReferenceを使用することで、実行時に実際のオブジェクトの参照を解決します。
参考URL:
https://docs.unity3d.com/560/Documentation/ScriptReference/ExposedReference_1.html
// もともとある、CreatePlayableメソッド内で、PlayableBehaviourを以下のようにインスタンス化 var behaviour = new TimelinePlayableBehaviour(); // Resolveメソッドを利用して、charaObjectの参照を実行時に解決します。 behaviour.charaObject = charaObject.Resolve(graph.GetResolver());
TimelinePlayableBehaviour.cs(コード全文)
using UnityEngine; using UnityEngine.Playables; // A behaviour that is attached to a playable public class TimelinePlayableBehaviour : PlayableBehaviour { public GameObject charaObject; public override void ProcessFrame (Playable playable, FrameData info, object playerData) { // PlayableTrackのClip上でシークバーが移動するたびに呼ばれ続ける(PrepareFrameの後) if(charaObject == null){ return; } var currentTime = (float)playable.GetTime() / (float)playable.GetDuration(); var currentPos = Vector3.Lerp(CharaDefine.START_POS, CharaDefine.GOAL_POS, currentTime); charaObject.transform.localPosition = currentPos; } }
Playable Behaviourにはあらかじめ規定のタイミングで呼ばれるメソッドが幾つか用意されています。
実行タイミングは以下になります。

Playable Behaviour
ProcessFrameは毎フレーム実行されるメソッドです。
var currentTime = (float)playable.GetTime() / (float)playable.GetDuration(); var currentPos = Vector3.Lerp(CharaDefine.START_POS, CharaDefine.GOAL_POS, currentTime); charaObject.transform.localPosition = currentPos;
現在時間 / 全体Durationでシークバーの位置を0-1で取得し、GameObjectのポジションを算出しています。
2つのPlayableオブジェクトを作成したら、Addボタンから、Playable Trackを選択し、追加されたTrackのTimeline上で右クリック>Timeline Playable Asset(作成しておいたPlayableAsset)を選択します。

Playable Assetの選択
最後にカメラの位置の調整をします。
カメラの移動・回転は、Timelineで直接Recordingしてみます。
AddボタンからAnimation Trackを選択し、Cameraを適用します。
Recordingボタンを押すと、ボタンが点滅し、CameraのPlayableAsset領域が赤くなりRecording…表示になります。
AnimationClipのカーブをいじる要領で動きをつけることができます。
メモ RecordingするとProjectウィンドウのTimelineの配下にRecordedという名前でClipが作成されます。 このClipは直接Deleteすることができません。Deleteしたい場合は、Timeline.playableファイルを テキストエディタで開き(YAML形式)、該当する名前を探して一連を削除することで、ClipもDeleteされます。 また、Timeline内のRecordedClipを複製(Cmd+D)することで、Timelineから外に「コピー」することが可能です

Recorded Clip
Timelineはこのようになりました。

Timeline 結果
このような感じでカメラのレコーディングと、Runの特定タイミングをスロー再生するようにしました。
スロー再生は、TimelineでスローにしたいAnimationClipを選択し、インスペクタパネルで、SpeedMultiPlierの数値を小さくすることで変わります。(デフォルトは1)
ただ、サンプルでは再生はスローですが、移動量はそのままなので完全なものを作るにはもう少し工夫が必要です。
また、カメラが追うという処理を入れると、タイミングと位置合わせを調整することが思ったように行きません。
カメラ自体を特定オブジェクトにLookAtするようなスクリプトをかけば解消されますが、Unity2017でリニューアルするCinemachineアセット (ベータ版公開中) を利用すれば、カメラが被写体のどこを映すかを設定出来たり、設定した対象とカメラの位置を同期したり、カメラのショットをもっと便利に作成することができます。

Cinemachine Base Rig
Timelineとの親和性も非常に高いので、次回はCinemachineアセットver2.0を導入し、TimelineでCinemachine.Timeline (Track)を 使ってみたいと思います。
この記事へのコメントはありません。