找回密码
 立即注册
查看: 399|回复: 2

【Unity】动画Graph插件的开发总结

[复制链接]
发表于 2023-1-31 16:11 | 显示全部楼层 |阅读模式
本文简单列出了动画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

发表于 2023-1-31 16:16 | 显示全部楼层
文中用 ~~ 包围的文字是加了删除线的,知乎没法识别这个Markdown语法,没能正常显示。
发表于 2023-1-31 16:18 | 显示全部楼层
补充一点,Playable可以通过PropertyStreamHandle实现读写Curve数据等:https://docs.unity3d.com/2021.3/Documentation/ScriptReference/Animations.PropertyStreamHandle.html
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-21 21:31 , Processed in 0.093087 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表