当前位置: 首页 > java >正文

【Unity博客节选】Playable系统 UML类图与结构分析

注:软件版本Unity 6.0 + Timeline 1.8.7

作者:CSDN @ RingleaderWang
原文:《Unity第25期——Timeline结构及其源码浅析》
文章首发Github👍:《Timeline结构及其源码浅析》

Bilibili 视频版👍👍:《Timeline结构及其源码解析》https://www.bilibili.com/video/BV1bHjYzNE35

Playable系统

前文介绍了Timeline的静态结构,为了更好地理解运行时Timeline,需要先了解底层的Playable系统。Playable 系统包括PlayableGraph、Playable和PlayableOutput。

下面依次介绍。

PlayableGraph

PlayableGraph管理Playable和PlayableOutput节点,控制整个节点树的运行。

PlayableGraph 与 PlayableDirector 类

Timeline 运行时会根据PlayableDirector的Playable参数创建PlayableGraph。

PlayableDirector可以用PlayableDirector.playableGraph属性获得创建的graph;
PlayableGraph也可以用PlayableGraph.GetResolver() as PlayableDirector 解析出PlayableDirector。PlayableGraph的很多方法都可以直接在PlayableDirector中调用。

PlayableGraph 和 PlayableDirector UML类图如下:

PlayableGraph的结构

对于前面的 timeline 资产:

在运行时形成的Graph结构如下:

PlayableGraph的构建过程:

  • PlayableDirector RebuildGraph触发构建graph动作
  • 根据director的TimelineAsset 创建 TimelinePlayable
  • 然后依次 编译所有track和clip,创建对应的MixerPlayable、PlayableOutput和Playable。
    • TimelinePlayable作为根节点,下一层是MixerPlayable或LayerMixerPlayable,叶子节点是包含clip的Playable。
    • Playable之间是通过Connect连接,PlayableOutput通过setSourcePlayable与TimelinePlayable连接。
  • 编译clips期间会build IntervalTree,为后续graph play作准备。

大体过程图如下:

Playable 的结构与类

PlayableGraph 中的 Playable 节点负责 数据的生产、传递与处理,包含叶子节点、mixer节点和layer节点等。

Playable结构

Playable是一个多输入多输出的有向节点,拥有speed、time、duration、isDone、PlayState等参数标识自身的运行状态,并对外提供控制自身运行、暂停与销毁的接口。

节点属性/方法
  • Playable节点拥有多个input port、多个output port用于连接其他Playable节点。
  • 节点连接前需保证port存在,否则报错Connecting invalid input/output,需要用SetInputCount()/SetOutputCount()申请端口,或者create时指明inputCount参数。
  • 同一port不能连接多个节点,否则报错Cannot connect input/output port, it is already connected, the tree topology will be invalid. Disconnect it first
  • Input有权重weight的概念,默认是0,可以在connect时指定weight或者用Playable.SetInputWeight(inputIndex, weight)设定输入权重
  • Playable节点间连接,可以使用PlayableGraph.Connect(...)或者扩展方法的Playable.ConnectInput(...)(默认权重为0)
PlayableGraph.Connect(...)bool Connect<U, V>(  U source,  int sourceOutputPort,  V destination,  int destinationInputPort)  where U : struct, IPlayable  where V : struct, IPlayable

允许的结构:

不允许的结构(三个节点首尾相接)(出现死循环,如果使用graph visulizer,unity会奔溃)

一些特殊的属性/方法
  • GetScriptInstance(),指明playable生命周期的回调方法
  • GetClip()/SetClip,一些包含Clip内容的Playable如 AnimationClipPlayable、AudioClipPlayable、AnimatorControllerPlayable、MaterialEffectPlayable、CameraPlayable、VideoPlayable 拥有存取此Playable绑定的可播放片段的方法。这些方法名不固定,根据Playable类型,也可以叫 Get/SetMaterial()、GetAnimatorController、Get/SetCamera()、GetAnimationClip()等。
运行属性/方法
  • Play statePuase/Playing,标识此节点运行状态
  • Speed:playable的播放速度
  • Play():运行playable
  • Pause():停止自身playable运行
  • IsDone:标识此节点运行完毕
  • Destroy():利用所属graph销毁自身Playable
  • TraversalModeMix/Passthrough,表示遍历节点input的方式,Mix就是将各输入进行加权;passthrough就是匹配input与output,第几个output来请求数据,就从第几个input获取数据。Passthrough目前只用于TimelinePlayable,使之成为graph的统一入口。

Playble UML类图

PlayableAsset创建的playable有两种,一种是不带生命周期管理的Playable,另一种是带生命周期管理的(实现IPlayableBehaviour接口)。第二种其实就是Timeline模块中基于ScriptPlayable实现的一种官方自定义playable。

基础Playable 的 UML 类图

注意这些Playable都是Struct,没有像class一样的继承能力,但这些子Playable都重写了隐/显式操作符,所以功能上等价于存在继承关系。比如下面AudioClipPlayable例子:

public static implicit operator Playable(AudioClipPlayable playable)  
{  return new Playable(playable.GetHandle());  
}  public static explicit operator AudioClipPlayable(Playable playable)  
{  return new AudioClipPlayable(playable.GetHandle());  
}// 自动转换
AudioClipPlayable audioClipPlayable = ...;
Playable playable = audioClipPlayable;// 需要显式转换
Playable playable = ...;
AudioClipPlayable audioClipPlayable = (AudioClipPlayable)playable;
  • 这些Playable都拥有Create方法,供TrackAsset执行CompileClips方法或CompileTrackPlayable方法期间调用。
  • Playable按功能大概分成两类
    • 一类如上面蓝色(AnimationClipPlayable等)和绿色(ScriptPlayable)的Playable,在graph中常作为叶子节点的,其内部是含有类似clip的属性,能getClip、setClip(有的没暴露set,只能在create时传入)。
    • 一类是上面黄底色的Playable,在graph中作为中间节点,可能包含多个输入,所以命名一般叫MixerPlayable、LayerPlayable,对多个输入的权重或其他数据进行处理。
  • 上面结构图并没有列出所有Playable,详细的可以查看IPlayable的所有实现。
  • ScriptPlayable比较特殊,能够接收PlayableBehaviour控制Playable的生命周期,这样形成的就是自定义Playable(Timeline里的很多Playable本质上就是这种官方自定义Playable)。

下面就详细介绍这些所谓的“官方自定义Playable”。

PlayableBehaviour 的 UML 类图

继承PlayableBehaviour的类分为几种:

  • TimelinePlayable:作为graph中所有其他playable的根父节点,控制所有clip的激活与否。
  • Audio的两个名字比较特别,叫AudioMixerPropertiesAudioClipProperties,AudioClipProperties甚至连一个回调都没有,这就涉及到PlayableBehaviour的第二种作用:传递PlayableAsset/TrackAsset参数给运行时的各生命周期。这种参数传递有两种用法,后面会介绍。
  • Activation有关的 ActivationControlPlayable 和 ActivationMixerPlayable 。
    比较好玩的是 ActivationControlPlayable 只用在 ControlTrack ,而 ActivationMixerPlayable 只用在 ActivationTrack 。
  • ControlTrack 的三个playable:
    • 控制粒子的ParticleControlPlayable
    • 控制prefab的PrefabControlPlayable
    • 控制PlayableDirector(也就是控制子Timeline)的DirectorControlPlayable

PlayableOutput 结构与类

PlayableOutput 作为 PlayableGraph 中的数据输出节点,在graph Play 时负责发起 Playable节点的遍历(没连PlayableOutput 对应的Playable不运行),并将Playable节点传递的数据交由对应的target运行。

PlayableOutput 结构

PlayableOutput 的结构相当简单。

  • ReferenceObject:对应的TrackAsset
  • SourcePlayable:PlayableOutput连接的Playable,使用扩展方法PlayableOutput.SetSourcePlayable(Playable value, int port)连接
  • 注意连接的SourcePlayable和port不能都一样,否则报错Cannot set multiple PlayableOutputs to the same source playable and output port
  • weight:PlayableOutput也拥有权重,默认为1,可以通过PlayableOutput.SetWeight(float value) 设置。
  • target:AnimationPlayableOutput、AudioPlayableOutput、TexturePlayableOutput拥有这个属性,表示Track所绑定的对象,用于后续处理Playable传过来的数据。

UML 类图

相比Playable的类图,PlayableOutput就显得眉清目秀了。

  • 跟Playable一样,PlayableOutput也是struct结构体,它的继承也是重载显隐操作符。
  • 每种PlayableOutput都有个create方法来创建一个具体的PlayableOutput。
  • 除了ScriptPlayableOutput外,都有个target参数用于指明track binding的target对象。

http://www.xdnf.cn/news/10017.html

相关文章:

  • window10下docker方式安装dify步骤
  • 动态IP与区块链:重构网络信任的底层革命
  • RK3399 Android7.1增加应用安装白名单机制
  • Android 开发 Kotlin 全局大喇叭与广播机制
  • 2025 年 Solana 生态全景分析:它如何从以太坊「高速替代方案」成长为成熟的基础设施?
  • [CSS3]响应式布局
  • 多卡训练核心技术详解
  • TreeMap、TreeSet和HashMap、HashSet
  • PCB设计实践(三十一)PCB设计中机械孔的合理设计与应用指南
  • 【Java学习笔记】接口
  • 解决开发者技能差距:AI 在提升效率与技能培养中的作用
  • 00 QEMU源码中文注释与架构讲解
  • 领域驱动设计 (Domain-Driven Design, DDD)
  • MyBatis操作数据库
  • Vue3使用vue-web-screen-shot实现截图功能
  • Windows SSDT Hook(二)
  • 【软件设计】通过软件设计提高 Flash 的擦写次数
  • 每日Prompt:指尖做画
  • kuboard自带ETCD存储满了处理方案
  • (21)量子计算对密码学的影响
  • EasyExcel复杂Excel导出
  • 测试用例篇章
  • C语言创意编程:用趣味实例玩转基础语法(4)
  • CIO大会, AI课笔记手稿分享
  • VScode ios 模拟器安装cocoapods
  • Java Spring Boot 自定义注解详解与实践
  • `docker commit` 和 `docker save`区别
  • 每日c/c++题 备战蓝桥杯(P1011 [NOIP 1998 提高组] 车站)
  • 论文速读《UAV-Flow Colosseo: 自然语言控制无人机系统》
  • If possible, you should set the Secure flag for these cookies 修复方案