Customizable Sequencer Tracks 插件调研与使用
在开发自定义 Sequencer 轨道期间,笔者发现官方提供了自定义轨道的能力,并且简单的使用蓝图就可以进行拓展。
通过使用蓝图和子类,你可以创建自定义类型的Sequencer轨道。这样,无需C++代码你就能扩展Sequencer轨道的功能。这在设计或实现项目新轨道时非常有用。
这一部分官方文档写的很好,读者也可以先跟随官方文档再来查阅本文。
此插件在4.26 版本添加到了 UE 中,但直到目前为止(UE 5.0.2,笔者版本),此插件仍然为测试版,或许其还不稳定,或存在一些其他问题,但对于自定义 Sequencer 的需求不一定多么复杂,官方提供的能力可能足以完成,因此本文中笔者主要尝试使用此插件,并对其源码调用原理进行分析。
插件将 C++ 的部分接口用 Instance 的细节面板属性进行控制,甚为巧妙,基于 C++ 实现自定义轨道开发并实现预览逻辑可以参考笔者本文
自定义 Sequencer 轨道开发。
一、尝试使用
1. 激活插件
当前版本插件仍然为测试版本,需要手动开启,按照下图所示,在虚幻主菜单中点击 Edit -> Plugin
在弹出的窗口中勾选 Customizable Sequencer Tracks 插件前的复选框以启用插件,然后重启引擎。
此时可能会弹窗提示,测试版本不稳定,点 Yes 即可。
Restart 后,会弹出此框,我们回到 IDE 中重新编译即可。
2. 创建新轨道
新建自定义Sequencer轨道需要先创建继承自以下蓝图的三个不同蓝图类:
- SequencerSectionBP
- SequencerTrackBP
- SequencerTrackInstanceBP
右键内容浏览器(Content Browser),点击添加蓝图类(Blueprint Class),然后在 所有类(All Classes) 部分中找到这三个类。每个都创建一个新的子级蓝图类。
接下来,我们需要将不同的类进行关联来让它们产生关联。
打开继承自 SequencerTrackBP 的蓝图 WxdTrack,并在 细节(Details) 面板的 类默认(Class Defaults) 部分设置以下属性:
-
将 默认片段类型(Default Section Type) 设为继承自 SequencerSectionBP 的新蓝图。
-
将 轨道实例类型(Track Instance Type) 设为继承自 SequencerTrackInstanceBP 的新蓝图。
-
TrackType 中,还可以指定轨道类型,看起来应该是 C++ 中的 Master Track 以及与 Actor 绑定的两种 Track。这里我们先不做调整,使用 MasterTrack 来进行测试。
编译并保存蓝图后,现在可以从 Sequencer 的添加轨道(Add Track) (+) 菜单添加一个主要轨道。
3. 创建轨道逻辑
此种方式完成的自定义轨道,所有的逻辑主要会在 TrackInstance 中完成,UE 提供了如下七个接口,实现这些接口,就可以完成我们的自定义功能。
接口的调用时机如下图:
官方给出的接口含义如下图:
写的很清晰,但还是打个日志看一看具体的执行流程。
一次播放的执行流程如下:
OnUpdate 实际中一帧会有4-5次调用,总之,在此处完成相应逻辑,即可完成 Sequencer 轨道自定义相关功能。
虽然接口足矣,但笔者并未找到类似于 C++ 中 TrackTemplate Evaluate 中 Gettime() 类似的方法,因此需要精确控制时机,操作预览效果的逻辑或许并不适合在此处进行。
但类似于控制状态之类的逻辑,使用此种方式开发轨道或许会较为容易。
简单看了看,功能还是差了一些,或许这也是还是测试版的原因吧。
后续有时间可能会再看看 UE 内如何桥接的这些接口,或许可以模仿,将 C++ 自定义轨道的流程简化一些。
4. 获取 Context 及 Player
根据评论大佬的补充,
USequencerTrackInstanceBP 的蓝图 Update 方法 由 OnAnimate() 调用,因此参考同样继承了 UMovieSceneTrackInstance 的 UMovieSceneCameraCutTrackInstance 可以了解获取 Context 相关参数的方法。
但是其中大多方法并没有支持 Blueprint,因此若要在蓝图中使用,还是需要自己实现一些蓝图函数库。
这里因为平时使用自定义轨道及继承 FMovieSceneEvalTemplate 流程开发时,常常用到 SequencePlayer,这里简单写了个蓝图函数尝试获取,这里简单返回了第一个,有需要也可以传入 Section 比对:
测试发现似乎只有在 Update 期间 GetInputs 返回的数组才不为空(实则还有OnEndUpdateInputs()),因此也只有此期间才能获取到 Context 以及 Sequence Player。
具体 Inputs 数组的填充逻辑没太仔细研究,看了下调用栈是事件队列驱动的,因此简单断了下执行顺序,没再深入研究,大体为:
USequencerTrackInstanceBP::OnInitialize()
USequencerTrackInstanceBP::OnBeginUpdateInputs()
USequencerTrackInstanceBP::OnInputAdded()
UMovieSceneTrackInstance::UpdateInputs() 执行完毕后会填充 Inputs 数组
USequencerTrackInstanceBP::OnEndUpdateInputs()
USequencerTrackInstanceBP::OnAnimate()
USequencerTrackInstanceBP::OnInputRemoved()
看调用顺序,如果需要缓存相关信息,可以在 OnEndUpdateInputs() 中执行,在 OnInputRemoved() 中清理,也算可以正常使用,或随取随用,与 UMovieSceneCameraCutTrackInstance 的 OnAnimate() 逻辑一致。
总而言之,虽然可以获取到相关上下文信息,但可能还需要自己封装一些 BP 方法,相较于 FMovieSceneEvalTemplate 的拓展流程或 UMovieSceneHookSection 的拓展流程并没有太大的优势,希望后续官方有更多的优化拓展吧:
Comments 2 条评论
博主 BlurryLight
OnUpdate
实际上是走的cpp里的OnAnimate()
函数。 在OnAnimate
里是可以拿到Context的,具体可以参考void UMovieSceneCameraCutTrackInstance::OnAnimate()
。 拿到Context就可以拿到Context->GetTime()了。博主 Santa Wang
@BlurryLight 看了一下确实是的,感谢大佬