注:软件版本Unity 6.0 + Timeline 1.8.7
作者:CSDN @ RingleaderWang
原文:《Unity第25期——Timeline结构及其源码浅析》
文章首发Github👍:《Timeline结构及其源码浅析》
Bilibili 视频版👍👍
:《Timeline结构及其源码解析》https://www.bilibili.com/video/BV1bHjYzNE35
TraversalMode:Mix/Passthrough
,表示遍历节点input的方式,Mix
就是将各输入进行加权;passthrough
就是匹配input与output,第几个output来请求数据,就从第几个input获取数据。Passthrough目前只用于TimelinePlayable,使之成为graph的统一入口。
⭐Traversal mode 验证
对Traversal mode这个参数的理解非常重要,不明白它的话,你会误以为每个PlayableOutput都会接收所有叶子节点的数据。
我们来创建个graph案例:
[Tooltip("false则mode是passthrough,true则mode是mix")]
public bool changeTraversalMode = false;
[Tooltip("false则PlayableOutput的source为playable1,true则为playable2")]
public bool changeSourcePlayable = false;//newInput system绑定空格键触发
public void BackspaceDown(InputAction.CallbackContext ctx)
{ if (ctx.performed) { ValidateTraversalMode2(changeTraversalMode,changeSourcePlayable); }
}private void ValidateTraversalMode2(bool _changeTraversalMode,bool _changeSourcePlayable)
{ DestoryGraph(graph); graph = PlayableGraph.Create(); var playable1 = Playable.Create(graph,1); var playable2 = Playable.Create(graph,2); var playable3 = Playable.Create(graph); playable3.SetTraversalMode(!_changeTraversalMode?PlayableTraversalMode.Passthrough:PlayableTraversalMode.Mix); var playable4 = Playable.Create(graph,4); var playable5 = Playable.Create(graph,5); playable3.SetInputCount(10); playable3.SetOutputCount(10); graph.Connect(playable3, 0, playable1, 0); graph.Connect(playable3, 1, playable2, 0); graph.Connect(playable4, 0, playable3, 0); graph.Connect(playable5, 0, playable3, 1); ScriptPlayableOutput output = ScriptPlayableOutput.Create(graph, "customOutput"); output.SetSourcePlayable(!_changeSourcePlayable?playable1:playable2,100);graph.Play();
}
当前中间Playable的 traversalMode是passthrough,可以看到只有port 0 这条线有数据传输。
改变PlayableOutput连在port 1 这端,数据又只接受input 1 这个port输入了。
而当 MODE 设为 MIX ,input 0 和 input 1 都接收数据。
通过这个例子,能大概理解 TraversalMode
遍历模式到底是什么意思。
不过要注意,按照Passthrough源码注释的本意:
应该是sourceOutputPort
的PlayableOutput
跟对应input位置的节点进行直通,但实测sourceOutputPort没起作用,实际上是由PlayableOutput在graph中的顺序决定,也就是下图中PlayableOutput前面的#0 #1 #2 标号(其实就是PlayableOutput数组的index)。
测试代码你可以发现SetSourcePlayable
的port你设50设100都不影响。
void ValidateTraversalMode()
{ DestoryGraph(graph); graph = PlayableGraph.Create("TraversalModeGraph"); ScriptPlayableOutput output = ScriptPlayableOutput.Create(graph, "customOutput"); ScriptPlayableOutput output2 = ScriptPlayableOutput.Create(graph, "customOutput2"); ScriptPlayableOutput output3 = ScriptPlayableOutput.Create(graph, "customOutput3"); var playable = ScriptPlayable<CustomClipBehaviour>.Create(graph); var playable2 = ScriptPlayable<CustomClipBehaviour>.Create(graph); var playable3 = ScriptPlayable<CustomClipBehaviour>.Create(graph); var playable4 = ScriptPlayable<CustomClipBehaviour>.Create(graph); var playable5 = ScriptPlayable<CustomClipBehaviour>.Create(graph); var mixer = ScriptPlayable<CustomMixerBehaviour>.Create(graph); mixer.SetTraversalMode(PlayableTraversalMode.Passthrough);//默认mode为mix,这里改为passthrough mixer.SetInputCount(10);// 很重要,否则连接报错:Connecting invalid input mixer.ConnectInput(4,playable,0,1); mixer.ConnectInput(6,playable2,0,1); mixer.ConnectInput(2,playable3,0,1); mixer.ConnectInput(8,playable4,0,1); mixer.ConnectInput(1,playable5,0,1); output.SetSourcePlayable(mixer,30);// 这个SetSourcePlayable的port根本没用,完全根据PlayableOutput顺序获取的 output2.SetSourcePlayable(mixer,50); output3.SetSourcePlayable(mixer,100); graph.Play();
}
但从Animation计算权重的过程也能看出,SourceOutputPort本意就是playable的output port。但实测中Playableout获取数据时并没有使用这个参数,更没有校验,你设多少都可以(只校验了不能重复绑定,但没校验port是否存在)。
如果是bug的话,官方可能需要做下面两个步骤进行修复:
- 每connect一个节点到TimelinePlayable,TimelinePlayable的outputCount加一(这样直通才有意义)
- 对每个Playableout从根节点TimelinePlayable开始遍历时,严格按照
TimelinePlayable.getInput(PlayableOutput.GetSourceOutputport())
获取绑定的Playable,而不是用PlaybleGraph
中类似PlayableOytput[]
数组的index
来get input playable。(注:Timeline生成的graph中PlayableOutput.GetSourcePlayable()
得到的就是TimelinePlayable
)