【Unity】动画Graph插件的开发总结
本文简单列出了动画Graph插件的目标、开发过程中遇到的一些问题以及开发后的结论,作为备忘。注意:此插件并不完善,仅供参考,请勿直接用于产品。
插件地址:https://github.com/SolarianZ/Puppeteer
目标
[*]开发一套与UE中的Animation Blueprint类似的运行时动画系统
[*]替代Animator Controller
[*]【扩展】更丰富的姿态控制(任意叠加)
[*]【扩展】运行时随时增、减、替换动画节点(未实现,但并不复杂)
[*]【扩展】提供自定义动画控制节点(AnimationScriptPlayable,逐骨骼控制)
[*]【扩展】子图复用
[*]【扩展】姿态复用(未完成,预期使用AnimationScriptPlayable实现)
[*]【扩展】可以按需加载动画资源,无需立即加载整个Animator Controller中的所有动画(未完成,但并不复杂)
[*]公开动画Graph控制接口,供外部调用(脚本或可视化编程工具),模拟UE的Event Graph
实现
[*]Editor中Graph编辑器UI使用UIToolkit中的GraphView实现
[*]节点数据使用ScriptableObject存储(图连接关系,自定义节点行为等)
[*]Runtime使用Playable重建Graph结构并控制其行为
[*]每个Editor节点在运行时创建1个对应的Runtime节点
[*]Runtime节点内部创建一个动画Playable,用于播放或处理动画(由PlayableGraph驱动,后序遍历)
[*]Runtime节点公开一个PrepareFrame方法,供父节点调用(前序遍历)
[*]【另一种实现方式】~~每个Editor节点在运行时有2个对应的Runtime节点,由PlayableGraph驱动其生命周期(这样PlayableGraph中就会有2结构颗树,一颗是动画Playable树,另一个是ScriptPlayable树)~~
[*]~~1个动画Playable节点,用于播放或处理动画~~
[*]~~1个ScriptPlayable节点,用于控制动画Playable节点(处理权重变化、状态机逻辑等)~~
[*]Runtime初始化时,需要遍历2次全部节点
[*]第1次遍历,初始化节点自身(注册变量变化事件监听、将节点注册到节点表中等)
[*]第2次遍历,根据自身记录的输入节点Guid,到节点表中查找输入节点,还原图连接关系
[*]Runtime的整个生命周期由PlayableGraph驱动
[*]动画根节点是一个ScriptPlayable,它负责调用输入节点的PrepareFrame方法,每帧完成一次前序遍历,用于修改动画Graph状态(更新各个节点权重,跳转状态机等)
[*]动画节点中的每个Playable对象,由PlayableGraph直接驱动,按照后续遍历顺序完成动画的处理
缺陷
[*]动画复杂时,运行时节点实例非常多,性能会变差
[*]Unity中存在托管和非托管代码间的通信开销(尤其是AnimationScriptPlayable节点,包含了太多的骨骼数据)
[*]ScriptPlayable影响PlayableGraph的多线程计算(ScriptingObjectPtr不为空的PlayableGraph被标记为了不可多线程处理,但不确定实际执行逻辑)
[*]Unity与UE的底层动画处理逻辑不同,导致动画Graph中只能“中途”处理动画“姿态”和“跟运动”,无法实现其他逻辑
[*]Unity只通过AnimationStream对动画Playable开放有限的姿态和跟运动控制接口,无法实现复杂逻辑
[*]Unity在PlayableGraph中直接完成了将动画姿态和跟运动应用到骨骼的过程,而不是输出姿态和跟运动,这导致动画Graph和Timeline没法无缝衔接
[*]UE的Animation Blueprint和蒙太奇都只输出姿态和跟运动,最后由USkeletalMeshComponent将其应用到骨骼
[*]【可能的解决方案】在Timeline中实现一个自定义动画Track,此Track不直接在Timeline中播放动画,而是控制动画Graph,使其动态增加一个动画分支并Blend到这个分支
[*]Unity没办法做到像UE一样在动画Graph中嵌入Event Graph来控制动画逻辑,只能对外暴露接口,供脚本或可视化编程插件使用
[*]如果使用脚本,那要求使用者会编程,图形化的动画Graph的意义就被弱化了,还不如全由脚本实现,然后提供一个可视化调试工具,性能更好,控制更灵活,可以按需添加动画节点,而不用加载整个动画Graph中的所有节点
[*]Bolt等可视化编程工具性能不佳,并且结构远不如UE的Event Graph清晰,实际使用感受是,能把Bolt用好的人,代码功底不会很差,不如直接写代码
[*]动画简单的游戏用不上,动画复杂的游戏,为何不用UE?
替代方案
[*]封装Playable接口,提供一个具有基础的动画Layer管理、动画混合管理功能的通用组件,项目的具体动画逻辑完全使用代码控制,不使用图形化编辑
[*]https://github.com/SolarianZ/UnityVisualPlayable/blob/main/Runtime/Scripts/AnimationBrain.cs
[*]提供可视化的动画调试工具,帮助调试
[*]https://github.com/SolarianZ/UnityPlayableGraphMonitorTool
文中用 ~~ 包围的文字是加了删除线的,知乎没法识别这个Markdown语法,没能正常显示。 补充一点,Playable可以通过PropertyStreamHandle实现读写Curve数据等:https://docs.unity3d.com/2021.3/Documentation/ScriptReference/Animations.PropertyStreamHandle.html
页:
[1]