入门视频:

https://www.bilibili.com/video/BV1SP4y177YQ

《永劫无间》的动作与运动系统

https://www.bilibili.com/video/BV1QN411f7WJ?t=197

相关文章

https://zhuanlan.zhihu.com/p/386710404

Playable API

简单的说,Playable可以通过一组API来创建一个Graph,而每个Graph可以由多个树形结构组成,每个树状结构都由一个Output节点作为根节点,叶子结点则由各种Playable组成。

它提供了一种创建工具,动画系统或其它游戏机制的方式。Playable Graph允许我们混合和修改多个数据源,并通过单个输出来播放它们。

目前Playable API 支持播放动画、音效以及自定义的行为。我们把它设计为了一种通用的接口,它并不是仅仅针对动画的。以后还会支持视频等其它系统。

为什么要开发这么一套API

在我们技术支持团队平时接触客户时发现,由于历史原因或者是出于习惯,依然有很多开发者在使用Legacy动画系统Animation组件。Legacy动画系统对于程序来说是比较直观的,但这就意味着没办法使用Mecanim动画系统的一些高级功能,例如:动画重定向、Blend Tree等。

首先,设计Playable API的一个目的就是为了代替Legacy动画系统。

开发人员可以用他们喜欢的方式来直接控制动画系统,而不是必须使用Mecanim系统的动画状态机来驱动动画系统。在Unity底层,驱动Playable Graph的实际上依然是Animator组件,所以在使用时需要你传一个Animator组件给Playable Graph。但是你完全可以像使用Animation组件一样使用Playable。

其次,我们还可以定制适配于自己项目的动画系统,而不用必须使用动画状态机来构建我们的动画逻辑。

这是一个非常有用,也非常有挑战性的工作。例如:有些有技术积累的公司,他们已经开发过自己的动画控制系统,这里不是指底层的动画驱动系统,而是更高层的动画控制系统,这套系统可能是架构在其它引擎上或是自研引擎上的。如果它们想要沿用这套系统的话,就可以用Playable来更方便的重构他们的控制系统,来适配到Unity上。更重要的是,我们可以定制更加适配于具体项目的动画系统。

再者,Playable API可以更直接的访问底层动画系统的接口。

最后,我们可以通过Playable来扩展Timeline的功能。

使用Playable有什么好处

首先Playable结构简单。它不会有庞大的、蜘蛛网一般的状态机。如果只是单纯播放动画的话,可能几句话就够了,使用起来就像Legacy Animation组件一样。如果是大型的RPG或FPS游戏,我们也没必要把大量的动画都添加到Graph中,我们可以预先创建好需要的子树,然后根据需要在添加到Graph中。

动画状态机是不允许运行时添加、删除动画的,它只能使用OverrideController来替换动画。这其实在开发中时是不太方便的。因为当动画数量非常多的时候,我们又没办法在运行时添加、删除State,这往往造成会生成一个巨大的状态机来满足所有可能的状态,而这个巨大的状态机维护起来是十分麻烦的。

在Animator状态机中,是通过定义变量来间接控制权重的。而在Playable中,你可以直接控制动画的权重和时间。例如:我们可以让二个动画按0.2和0.8的权重混合。Playable的这种方式是更加灵活的,但是相对的它对于普通开发者实际上是没有Animator parameter方便的。

我们不仅能在二个Animation clip之间混合,我们也可以在Clip和AnimatorController之间混合,甚至无数个AnimatorController之间混合都是可以的。这就给我们带来了更多的便利:在动画状态机加这个系统中,二个State machine之间是不能过度的,但是如果使用了Playable,那就是可行的。所以我们完全可以混用Animator状态机和Playable。一些角色的固定动画状态的转变我们可以继续用动画状态机,而那些需要动态改变的功能我们就用 Playable。

基本架构

Playable API大体上有二部分组成:各种Playable和PlayableOutput。

Playable是我们这套API的基本组成元素。为了避免Gc alloc,所有的Playable是用Struct实现的。PlayableOutput是每个Graph必须的组成元素。而且PlayableOutput必须连接到至少一个Playable上,否则它是没有任何作用的。

注意:上图中所列的Playable结构是不全的,因为后续版本还会不断有新的Playable被添加进来。

Playable Graph

让我们先从图形入手,对Playable Graph有一个直观的认识。下图是一个很简单的Playable Graph。

我们可以看到这里有二个节点:一个Animation clip节点和一个Output节点。这里实现的功能很简单,就是播放一个动画。这是一个Playable节点形成的一个非常简单的树形结构,基本上,每一个PlayableOutput都会形成一颗树形结构。

让我们来看一个稍微复杂点的例子。

一个树形结构一般由一个输出节点,若干个输入节点以及若干个功能节点组成。在上图中,有一个输出节点Animation Output,二个输入节点Animation clip以及二个功能节点。这个Graph实现的是二个动画作为2个Layer来融合,可以看作和动画状态机中的Layer是一样的功能。

如果单看动画这一部分的话,Playable graph本质上就是一颗动画混合树。注意:这里指的这个混合树并不是Blend Tree,而是一个更广泛的概念。它的内部节点是运算符,主要起到混合的作用,而叶节点是输入。

现在,我们来看一个更复杂一点的例子。

这是由三颗树形结构组成的一个Playable Graph。它由Animation output、Audio output以及Script output 三个输出节点。可见一个Playable Graph不仅仅可以包含动画,它是一个更广泛的概念,你可以在播放动画的时候同时播放音效以及自定义的逻辑。

Playable用途

通过以上的介绍,大家应该能对Playable Graph有一个直观的、简单的认识。那么Playable又能实现哪些功能呢?接下来我们就深入了解一下。

首先,我们可以用Playable API代替Animation组件。这使得我们在满足Legacy动画系统的机制的同时,我们还可以获得其它好处,例如:Blend Tree、动画重定向等。

这里给出一个官方的示例,主要用Playable API来模拟了一套动画状态机,以类似Animator动画状态机的机制来使用Playable,大家可以参考一下。

官方的示例下载:

https://github.com/Unity-Technologies/SimpleAnimation

再就是按照项目的需求来定制了。你可能并不喜欢用动画状态机来管理动画,也有可能你想要实现一个自动评估transition的系统,使系统可以评估当前状态,自动过渡到最理想的动画等等。Playable API是提供给了大家按需定制的功能。

运行时创建

我们的Playable Graph都需要在运行时创建,目前它还没有一个默认的Asset来供使用。不过开发者完全可以自己来创建自己的Asset来序列化自己想要的Graph结构,然后运行时通过Asset来反序列为Graph。

下面是创建一个简单的Graph的代码。

从上图可以看到,Playable结构都是以工厂方法Create来创建的。通过这段代码创建的Graph就是下图这样的,十分简单。

运行时添加

在运行时,可以创建你想要的Playable并且连接到对应的输出节点或者另一个Playable上。

在用工厂方法创建好AnimationClipPlayable结构后,需要通过Graph.Connect方法来连接到Graph中。

下图就是这段代码添加二个Playable后的Graph的样子。

运行时移除和销毁

类似的,我们也可以在运行时动态修改Graph的结构,以及销毁指定的Playable。

直接访问与控制Playable

我们可以直接控制每一个Playable的属性,例如播放速度。我们甚至可以暂停一个动画把它当作一个Pose来使用。

其次我们可以控制每一个Playable的混合权重,通过控制权重,我们就可以实现类似Blend Tree、Transition等功能。

我们还可以控制更新频率,这在我们做动画的性能优化时比较常用,例如:那些距离Camera过远的角色我们就可以把动画的更新频率降低。

要方便的控制每一个Playable还需要我们做一些额外的工作。这是因为:想象一颗非常深的树形结构,你想访问或控制非常深的一个叶节点实际上是不太方便的。当然你可以保存起它的引用,不过那通常不太灵活,像是写死在代码中一样,一个二个还好,但是你不可能把所有的都存下来。所以这就需要我们做一些额外的工作来管理和访问Playable。例如:提供一个查询叶子节点的接口或者实现一个类似Animator parameter系统来和Playable的属性进行映射。

Transitions

Playable API 中没有专用的Transition功能,它没有类似动画状态机中二个state之间拉一个线段来定义Transition。这是因为Transition本质是二个动画的Blend,所以Playable API没有提供专用的Transition功能,而是提供给应用层基本的Blend功能,应用层根据自己的需求来实现Transition。

这样就给了我们更多的可能性。除了经常使用的平滑过渡以外,我们还可以实现其它类型的过渡,例如:冻结过渡,也就是由动画A过渡到动画B时,A就不在更新了。而动画B在更新的同时Weight由0变为1。这种过渡方式比较适合那些前后二个动画差异较大的情况。另外我们为了更圆滑的过渡,我们还可以控制过渡时的曲线,例如:使用Hermit曲线。

这给我们带来了更佳灵活、自由的控制方式。现在的动画状态机使用起来虽然方便,仅在二个State之间拉一条线就可以了.但是我们想要精确的控制Transition却比较困难。例如:有这么个需求,服务器和客户端动画的同步问题。如果用Animator来做的话,是很难做到完美的。因为Transition你在外部是不能直接控制的。而如果用Playable的话,我们只需要同步二个动画的ID,以及它们的权重和Transition的持续时间就可以了。

Animation Layer

Playable API同样可以实现骨骼分部混合和加法混合,类似于Animator中的Layer功能。这在我们混合全局姿势和局部姿势时会非常有用。比如RPG中上下半身的动画,像是边跑边攻击之类,或者是FPS中角色边跑边换枪以及瞄准姿势等。我们也可以运行时动态的增加、删除Layer,如下图所示。

通过设置AnimationLayerMixerPlayable的input weight来控制混合。一个基本的Animation layer混合如下图所示。

Blend Tree

我们也可以用Playable实现Blend Tree来混合动画。

这段代码相当于实现了一个最简单的1D Blend Tree。

通过AnimationMixerPlayable来进行混合,并且通过Input weight来控制混合过程。为了保证动画的准确性,AnimationMixerPlayable的混合权重在内部会保证和为1。

虽然Playable可以定制Blend Tree的混合方式,但是个人觉得对于一般的开发者来说目前过于繁琐了。比如2D Blend Tree中的三元混合,你需要以三角形质心坐标系来计算三个输入的权重。因此对于Blend Tree,大家不如直接使用动画状态机中的Blend Tree,那样更为方便。

与Animator Controller混合使用

首先,Playable可以和Controller叠加分层动画。在动画状态机中Layer是Static的。所以利用Playable和Animator controller混合就可以起到动态添加你想要的Layer的作用。

其次,Playable可以和Controller进行混合,你可以让它们按一定的权重进行Blend。

再者,Playable可以和Controller互相CrossFade。例如:我们有一把武器,想要让武器来告诉角色该怎么使用这把武器。所以我们创建一个Animator controller放在武器上,当角色拿起武器后,就可以CrossFade到武器的动画状态机上。这可以让大大降低我们的动画系统的复杂度,因为动画的CrossFade不在局限于一个状态机里了。

最后,二个Controller可以进行混合。例如:你可以从一个状态机Crossfade到另一个状态机上。

控制多个输出

一个Playable Graph中不是只能有一个Output。除了动画的Output,我们还能添加其它种类的Output,例如:Audio output或者Script output. 这给了我们同时播放不同种类的Playable的能力,我们可以在动画的某一时间点播放一个音效。

上面段代码会生成下图的Graph。

PlayableBehaviour

PlayableBehaviour是一个供用户自定义行为的类。我们可以对Playable进行直接的访问和控制。同时它也定义了一些回调函数来捕捉一些事件。例如:开始播放时的事件、销毁事件,我们想监控这些事件时就离不开PlayableBehaviour这个类。

更重要的是,它提供了一些在每一帧的动画计算流程上的回调。例如:PrepareFrame函数会在Prepare frame这个阶段回调。我们就可以在每一帧对Playable中的元素进行访问和设置,例如:Time和Weight。可以说这是在做自定义Blend中不可缺失的功能。

举个例子:你想把子弹时间和人物射击动画的时间联系起来,你可以在PrepareFrame或ProcessFrame中获取射击动画的Normilized time,来修改游戏的Time.scale。

PlayableGraph Visualizer

PlayableGraph Visualizer是一个查看Playable graph结构的工具,这个工具目前来看还有些简单,它只能查看Graph的结构,没有编辑功能。但是对于Debug或者了解Playable graph的运行过程还是有帮助的。

PlayableGraph Visualizer下载地址:

https://github.com/UnityTech/graph-visualizer

未来展望

在Playable未来的开发中,我们会逐渐加入更多功能,例如: Procedural Animation与C# Job System相结合、Custom mixer、Motion stream等等。Procedural animation: IK, full body IK或者是FPS中举枪瞄准的动画。

结合C# Job System,可以让你的Playable运行在一个高效的、线程安全的子线程中,而

Custom mixer,可以定制你自己的mixe,Motion stream,一个特殊的Node可以直接播放一个Pose。

Unity Playable动画系统取代蜘蛛网Animator的更多相关文章

  1. Spine学习七 - spine动画资源+ Unity Mecanim动画系统

    前面已经讲过 Spine自己动画状态机的动画融合,但是万一有哥们就是想要使用Unity的动画系统,那有没有办法呢?答案是肯定的,接下来,就说说如何实现: 1. 在project面板找打你导入的Spin ...

  2. Unity 动画系统 Animation 和 Animator的小实例

    本文结合一个很简单的动画demo,分别采用2种方法,来对比Animation和Animator的使用方式: 方法1:单独使用Animation 方法2:Animation结合Animator 动画De ...

  3. Unity 动画系统 Animation和Animator 常用小功能

  4. Unity 动画系统 Animation和Animator等常用类

  5. Unity 动画系统 Animation 和 Animator 联系与区别

  6. Unity Mecanim 动画系统

    1. Animator 组件 Controller:使用的Animator Controller文件. Avatar:使用的骨骼文件. Apply Root Motion:绑定该组件的GameObje ...

  7. unity 对Animator动画系统的研究

    unity的新动画系统叫Mecanim,使用Animator来取代旧系统Animation,按Unity文档的惯例:知识点主要分2部分:unity manual和unity script,读者可以边看 ...

  8. Unity Animation System(动画系统)

    动画系统: 支持:动画融合,混合,叠加动画,行走循环的时间同步,动画层,控制动画的各个方面(时间,速度,融合权重)   带有每顶点1.2或4骨骼的蒙皮网格,以及支持基于物理的布娃娃系统和程序动画.   ...

  9. Unity3D之Mecanim动画系统学习笔记(五):Animator Controller

    简介 Animator Controller在Unity中是作为一种单独的配置文件存在的文件类型,其后缀为controller,Animator Controller包含了以下几种功能: 可以对多个动 ...

  10. Unity 4.0 中的新动画系统——MecAnim

    分享一个文档资料,关于动画系统的,版本应该很老了,但是有借鉴意义的: Unity 4.0 已于 2012 年 11 月 15 日正式发布,Unity 每一次版本的提升,都给游戏开发者带来惊喜,这一次也 ...

随机推荐

  1. 鸿蒙Next开发实战教程:实现抖音长按快速评论特效

    开篇点题,今天玩点花的. 不知道大家有没有发现,抖音上的评论键长按会弹出一排表情框用于快速评论,不过现在鸿蒙原生版的抖音还没有这个功能,今天幽蓝君就小试牛刀,在鸿蒙上做一下这个功能,也是应一位友友的私 ...

  2. P1758 [NOI2009] 管道取珠 题解

    题意: 有点复杂,看 原题面 吧. 思路 发现可以等价为两个人独立操作操作出来的序列相同的方案数. 然后发现复杂度阈值可以接受 \(n^3\),因此直接套路地设 \(f_{t,i,j}\) 表示两个人 ...

  3. 网络编程:UDP网路编程

    参考:盛延敏:网络编程实战 一.UDP和TCP的不同 UDP 是一种"数据报"协议,而 TCP 是一种面向连接的"数据流"协议. TCP 是一个面向连接的协议, ...

  4. Java安全01——URLDNS链分析与利用

    URLDNS链分析与利用 作用 URLDNS 利用链只能发起 DNS 请求,不能执行命令,所以用于漏洞的检测 不限制JDK版本,使用Java内置类,无第三方依赖要求 可以进行无回显探测 利用链 ​ 利 ...

  5. SmolVLM2轻量级视频多模态模型,应用效果测评(风景、事故、仿真、统计、文字、识物)

    SmolVLM2轻量级视频多模态模型,应用效果测评 目       录 1.     前言... 2 2.     应用部署... 2 3.     应用效果... 4 1.1          风景 ...

  6. pytest.mark.parametrize 传参

    pytest.mark.parametrize 是pytest用来参数化测试的一个装饰器,它允许你为测试函数或测试类提供多组参数list, 这样就可以使用每组参数执行测试函数或测试类,实现参数化驱动, ...

  7. CF1835D Doctor's Brown Hypothesis

    D - Doctor's Brown Hypothesis 首先,一对合法的\((x,y)\)一定是在同一个\(scc\)中的,所以我们将每个\(scc\)分开处理 若我们当前在处理某一个\(scc\ ...

  8. Windows系列操作系统,跳过开机密码直接登录

    要让 **Windows 11** 在启动时 **自动登录**,跳过开机输入密码,通常不推荐直接修改注册表来实现,但如果你希望使用注册表实现这个效果,可以按如下方式操作: --- ## 方法:修改注册 ...

  9. PHP:多级目录删除

    <?php // Author: windlike // Create Time: 2007-07-10 // Blog: windlike.cublog.cn function delDir( ...

  10. Web 服务器架构选择深度解析

    在 Web 服务与 API 设计中,服务器架构的选择直接决定系统的可扩展性.维护成本与性能上限.本文从架构演进脉络出发,系统解析单体架构.微服务.服务网格.Serverless 等主流架构的核心特性. ...