Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Timeline エディター拡張入門
Search
Yuichiro MUKAI
May 10, 2024
Programming
2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Timeline エディター拡張入門
2024/05/10 に開催された「Unity Timeline/Playable API 完全に理解した 勉強会」の登壇資料です。
Yuichiro MUKAI
May 10, 2024
More Decks by Yuichiro MUKAI
See All by Yuichiro MUKAI
MasterMemory v3 最速確認会
yucchiy
0
1.9k
Other Decks in Programming
See All in Programming
FreeBSDでZabbixを動かす
kenkino
0
340
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
19
20k
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
140
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
260
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
240
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
330
mrbgem 三角測量 開発
ogom
0
170
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
570
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
8
5.3k
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1k
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
280
Featured
See All Featured
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
[SF Ruby Conf 2025] Rails X
palkan
3
1.4k
Thoughts on Productivity
jonyablonski
76
5.4k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
270
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
300
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
510
Chasing Engaging Ingredients in Design
codingconduct
0
340
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
900
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
How Software Deployment tools have changed in the past 20 years
geshan
2
34k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Transcript
Unity Timeline/Playable API શʹཧղͨ͠ ษڧձ 2024/05/10 Ҫ ༞Ұ Timeline エ
デ ィター拡張入門
自己紹介 向井 祐一郎 • 株式会社 サイバーエージェント / 株式会社アプリ ボ ット
• Lead Developer Experience • システム系の基盤開発・プロジェクトの開発支援 SNS・個人活動など • @yucchiy_(X) • Unity Weekly • https://blog.yucchiy.com/tags/unity-weekly/ • UniTips(社内有志で技術書典に執筆)
• タイムラインのエ デ ィター拡張について概要の紹介 • TrackEditorとClipEditor • TrackEditorとClipEditorを用いた拡張の実例の紹介 • 見た目の調整やエラーメッセージの表示
• トラックのバインドオブジェクトの制御 • 生成・ 編 集時コールバックの取得 このLTで話したいこと
TrackEditorとClipEditorについて
TrackEditorとClipEditor • Timeline 1.1.0(2019/02/14)で追加された、トラックやクリップの エ デ ィター拡張 • UnityEditor.Editorのタイムライン版、といった立ち位置 •
トラックやクリップのエ デ ィターの挙動を制御できる • 見た目の調整やエラー表示 • トラックやクリップの追加・ 編 集時への処理の差し込み • トラックのバインドオブジェクトの制御 • etc…
標準トラックにおける拡張 事例 AudioClipの音声を波形情報として クリップの背景に表示したり バインドされたコン ポ ーネントがdisableなので エラーメッセージを表示したり
SampleTrackに対するエ デ ィターを作る TrackEditorの作り方 [CustomTimelineEditor(typeof(SampleTrack))] public class SampleTrackEditor : TrackEditor
{ public override void OnCreate(TrackAsset track, TrackAsset copiedFrom) { Debug.Log($"SampleTrack͕࡞͞Ε·ͨ͠ʂ"); } } CustomTimelineEditor属性をつけ、 対象のトラックの型を指定 用途に応じてメソッドをオーバーライドして処理を書く TrackEditorを継承
SampleTrackEditorの動作確認
SampleClipに対するエ デ ィターを作る ClipEditorの作り方 [CustomTimelineEditor(typeof(SampleClip))] public class SampleClipEditor : ClipEditor
{ public override void OnClipChanged(TimelineClip clip) { Debug.Log($"ΫϦοϓ͕ฤू͞Ε·ͨ͠ʂ"); } } CustomTimelineEditor属性をつけ、 対象のクリップの型を指定 ClipEditorを継承 用途に応じてメソッドをオーバーライドして処理を書く
SampleClipEditorの動作確認
TrackEditorでオーバーライドできるメソッド一覧 https://docs.unity3d.com/Packages/
[email protected]
/api/UnityEditor.Timeline.TrackEditor.html 見た目調整 & エラー処理 トラック操作時のコールバック トラックへのバインド オブジェクトの制御
ClipEditorでオーバーライドできるメソッド一覧 https://docs.unity3d.com/Packages/
[email protected]
/api/UnityEditor.Timeline.ClipEditor.html クリップ操作時のコールバック 見た目調整 & エラー処理 クリップ下へのタイムラインネスト制御
トラック/クリップの見た目を調整する
GetTrackOptionsをオーバーライドし、独自のTrackDrawOptionsを返却する GetTrackOptionsによる見た目の調整 [CustomTimelineEditor(typeof(SampleTrack))] public class SampleTrackEditor : TrackEditor { public
override TrackDrawOptions GetTrackOptions( TrackAsset track, Object binding) { var options = base.GetTrackOptions(track, binding); options.icon = AssetPreview.GetMiniTypeThumbnail(typeof(Rigidbody)); options.trackColor = Color.yellow; return options; } }
[CustomTimelineEditor(typeof(SampleTrack))] public class SampleTrackEditor : TrackEditor { public override TrackDrawOptions
GetTrackOptions( TrackAsset track, Object binding) { var options = base.GetTrackOptions(track, binding); options.errorText = track.GetClips().Count() switch { 0 => "ΫϦοϓΛઃఆ͍ͯͩ͘͠͞ʂ", 1 => string.Empty, _ => "ΫϦοϓ1͔ͭ͠ઃఆͰ͖·ͤΜʂ" }; return options; } errorTextにテキストを埋めることで、エラーメッセージを表示できる GetTrackOptionsでのエラーテキスト表示 クリップ一覧はTrackAsset.GetClipsで取得できる bindingには、トラックにバインドされた オブジェクトが渡ってくる
GetClipOptionsをオーバーライドし、独自のClipDrawOptionsを返却する GetClipOptionsによる見た目の調整 [CustomTimelineEditor(typeof(SampleClip))] public class SampleClipEditor : ClipEditor { public
override ClipDrawOptions GetClipOptions(TimelineClip clip) { var options = base.GetClipOptions(clip); options.highlightColor = Color.yellow; options.errorText = clip.duration < 1.0 ? "ΫϦοϓͷ͞1ඵҎ্ʹ͍ͯͩ͘͠͞ʂ" : string.Empty; return options; } } 各クリップごとにGetClipOptionsが呼び出され、 クリップ情報が引数に渡される
引数にクリップとその背景の領域が渡されるので、その領域にテクスチャを描画する DrawBackgroundによるクリップの背景の調整 [CustomTimelineEditor(typeof(SampleClip))] public class SampleClipEditor : ClipEditor { public
override void DrawBackground( TimelineClip clip, ClipBackgroundRegion region) { var tex = new Texture2D(128, 1); for (var x = 0; x < tex.width; x++) { tex.SetPixel(x, 0, Color.Lerp(Color.blue, Color.green, (float)x / tex.width)); } tex.wrapMode = TextureWrapMode.Clamp; tex.Apply(); GUI.DrawTexture(region.position, tex); } } 背景の矩形情報がRectで渡ってくるので、 その位置にGUI.DrawTextureなどで描画する エディターの定期更新で呼び出されるので、 テクスチャのキャッシュ等でパフォーマンスの工夫が必要
トラックへのオ ブ ジェクトの バイン デ ィン グ 挙動を調整する
IsBindingAssignableFromによって、オ ブ ジェクトのバインド判定を独自に定義できる IsBindingAssignableFromの活用 [CustomTimelineEditor(typeof(SampleTrack))] public class SampleTrackEditor : TrackEditor
{ public override bool IsBindingAssignableFrom( Object candidate, TrackAsset track) { var go = candidate as GameObject; if (go == null) return false; return go.TryGetComponent(out ISample _); } public override Object GetBindingFrom( Object candidate, TrackAsset track) { if (candidate is GameObject go) return go.GetComponent<ISample>() as Object; return null; } } IsBindingAssignableFromでfalseを返せば、 トラックへのオブジェクトバインディングを 拒否できる 実際にどのオブジェクトを トラックへバインドするかを指定できる (通常やれない)特定のインターフェイス を実装したコン ポ ーネントのバインド、ができる
トラック/クリップの追加・ 編 集を 検知する
それ ぞ れ OnCreate・On(Track|Clip)Changedというコールバックから取得可能 トラック/クリップの生成・ 編 集タイミン グ の取得 [CustomTimelineEditor(typeof(SampleTrack))]
public class SampleTrackEditor : TrackEditor { public override void OnCreate( TrackAsset track, TrackAsset copiedFrom) => Debug.Log($"SampleTrack͕࡞͞Ε·ͨ͠ʂ"); public override void OnTrackChanged( TrackAsset track) => Debug.Log($"SampleTrack͕ߋ৽͞Ε·ͨ͠ʂ"); }
クリップの振る舞いを制御できる(サ ポ ートする機能を報告する) 余談: ITimelineClipAsset.clipCaps [Flags] public enum ClipCaps {
None = 0, Looping = 1 << 0, Extrapolation = 1 << 1, ClipIn = 1 << 2, SpeedMultiplier = 1 << 3, Blending = 1 << 4, AutoScale = 1 << 5 | SpeedMultiplier, All = ~None } クリップをブレンドやループが可能か、 スケールした際の挙動、クリップ外の挙動など をフラグとして複数指定できる。 public interface ITimelineClipAsset { ClipCaps clipCaps { get; } }
クリップを重ねた際に、クリップを ブ レンドできることを示す機能 ClipCaps.Blending public class SampleClip : PlayableAsset, ITimelineClipAsset
{ public ClipCaps clipCaps => ClipCaps.Blending; }
クリップの範囲外の挙動を設定する ClipCaps.Extrapolation public class SampleClip : PlayableAsset, ITimelineClipAsset { public
ClipCaps clipCaps => ClipCaps.Extrapolation; } public class SampleBehaviour : PlayableBehaviour { public override void ProcessFrame( Playable playable, FrameData info, object playerData) { // ͨͩ͠Playable.GetDuration()ͷऔΓѻ͍ҙ Debug.Log($"{playable.GetTime()} / {playable.GetDuration()}"); } }
Extrapolationを設定すると、クリップ範囲外でもProcessFrameが呼 び 出される ClipCaps.Extrapolation の挙動
TimelineClipをTrackAssetからClipに渡して、Behaviourから参照する ClipCaps.Extrapolationにおけるdurationの取得 - 1 public class SampleTrack : TrackAsset {
public override Playable CreateTrackMixer( PlayableGraph graph, GameObject go, int inputCount) { var playable = ScriptPlayable<SampleMixer> .Create(graph, inputCount); foreach (var timelineClip in GetClips()) { var clip = timelineClip.asset as SampleClip; clip.TimelineClip = timelineClip; } return playable; } } public class SampleClip : PlayableAsset, ITimelineClipAsset { public TimelineClip TimelineClip; public override Playable CreatePlayable( PlayableGraph graph, GameObject owner) { var playable = ScriptPlayable<SampleBehaviour> .Create(graph); var behaviour = playable.GetBehaviour(); behaviour.Clip = this; return playable; } } TimelineClip.durationには正しい(?) Durationが入っているので、それをClipに渡し… https://blog.yucchiy.com/2019/11/how-to-access-clip-timing-in-playablebehaviour-with-unitytimeline/
public class SampleBehaviour : PlayableBehaviour { public SampleClip Clip {
get; set; } public override void ProcessFrame( Playable playable, FrameData info, object playerData) { var normalizedTime = playable.GetTime() / Clip.TimelineClip.duration; Debug.Log($"t = {normalizedTime}"); } } TimelineClipをTrackAssetからClipに渡して、Behaviourから参照する ClipCaps.Extrapolationにおけるdurationの取得 - 2 public class SampleClip : PlayableAsset, ITimelineClipAsset { public TimelineClip TimelineClip; public override Playable CreatePlayable( PlayableGraph graph, GameObject owner) { var playable = ScriptPlayable<SampleBehaviour> .Create(graph); var behaviour = playable.GetBehaviour(); behaviour.Clip = this; return playable; } } さらにClipをBehaviourに引き回して、 BehaviourからTimelineClipを参照する https://blog.yucchiy.com/2019/11/how-to-access-clip-timing-in-playablebehaviour-with-unitytimeline/
正しく(?)正規化時間が算出できることが確認できた ClipCaps.Extrapolationにおけるdurationの取得 -3
まとめ
• TrackEditorやClipEditorの基本的な使い方について紹介しました • TrackEditorやClipEditorを継承したうえで、 差し込みたい処理をメソッドのオーバーライドで実装する • TrackEditorやClipEditorの活用方法について説明しました • Get(Track|Clip)Optionsによる見た目の調整やエラーメッセージ表示 •
IsBindingAssignableToによるオブジェクトバインドの挙動制御 • OnCreateやOn(Track|Clip)Changedを用いたイベントのフック まとめ