在Unity 2018.2中,Animation C# Jobs通过使用在Unity 2018.1中推出的C# Job System扩展了动画Playables。在实现动画系统时,Animation C# Jobs让开发者能自由创建原始解决方案,同时使用安全的多线程代码来提高性能。

Animation C# Jobs是一个底层API,使用它需要对Playable API有充分的了解。使用Animation C# Jobs,你可以编写在PlayableGraph中用户定义位置调用的C#代码。用户自定义的C#脚本可以修改经过PlayableGraph的动画流。

Animation C# Jobs针对有兴趣将Unity动画系统扩展更多功能的开发人员,使用它可以充分利用现代多核硬件的强大功能。对于在主线程上C#脚本性能消耗较大的项目,可以并行化一些动画任务,让性能得到宝贵的提升。

功能
Animation C# Jobs拥有以下功能:
全新Playable节点:AnimationScriptPlayable 控制PlayableGraph中的动画数据流 多线程C#代码

特别提示:
Animation C# Jobs目前仍是一个实验性功能,具体API在UnityEngine.Experimental.Animations。该API之后会根据用户反馈改进。

适用场景
Animation C# Jobs适用以下示例场景:

例如:你想给全新的龙角色加入一个足部锁定功能。可以使用常规MonoBehaviour对其进行编码,但在动画播放结束之前所有代码都将在主线程中运行。如果使用Animation C# Jobs,你可以编写算法并将直接在PlayableGraph中的自定义Playable节点中使用它,代码将于PlayableGraph处理期间在独立线程中运行。

你还可以不用特地设置龙尾部的动画,通过Animation C# Jobs将能完美设置程序化计算动作的功能。Animation C# Jobs还能让你编写具体的LookAt算法。例如:帮助定位龙颈部的10块骨骼。

另一个很好的示例是制作自定义的动画混合器。假设你有一些具体需要的内容:该节点会从一次输入中获取位置,从另一次输入获取旋转角度,从第三个节点获取缩放值,然后将它们混合为单个动画流。Animation C# Jobs能帮助你实现创意的功能,并根据特定需求进行构建。

获取示例
在深入了解如何使用Animation C# Jobs API之前,让我们参考一些示例,它们将展示了使用Animation C# Jobs可以实现什么。

所有示例都可以访问Animation Jobs Samples的GitHub页面获取。安装完成后,示例中自带场景存放在Scenes目录下。

下载地址:https://github.com/Unity-Technologies/animation-jobs-samples

030207ppccvxa1xbnndz3m.png

示例解析
下面我们将为大家一一解析这些示例。

1、LookAt
LookAt是一个非常简单的示例,它将骨骼朝向一个效应器。如下图所示,你可以了解它如何应用于3D Game Kit资源包中的角色对象。
030211d6r7rxenp6pu24j1.gif

2、TwoBoneIK
TwoBoneIK实现了一个简单的双骨骼IK算法,它能应用于三个连续关节。例如:人类手臂或腿。演示中的角色使用通用Humanoid Avatar制作。
030217rfiyfy3051iarour.gif

3、FullbodyIK
FullbodyIK展示如何修改Humanoid Avatar上的数值。例如:目标、提示、观察对象和身体旋转等。下图示例使用了动画流的人形实现。
030223de212zpfgiiddd26.gif

4、Damping
Damping展示了实现可应用于动物尾巴或人类马尾辫的阻尼算法,说明了如何生成程序化动画。
030230m3cwa59zoo32j9e3.gif

5、SimpleMixer
SimpleMixer是一个非常基础的动画混合器。它接收二个输入流,然后将它们基于混合数值结合起来,功能类似AnimationMixerPlayable 。
030236rsiigijhzdajdc67.gif

6、WeightedMaskMixer
WeigthedMaskMixer示例是一个较高级的动画混合器。它接收二个输入流,然后将它们基于权重遮罩混合起来,该权重遮罩会定义如何混合各个关节。例如:你可以播放经典闲置动画,然后从另一动画剪辑接收手臂动画。或是通过在脊骨上连续应用较高的权重来平滑上身动画的混合效果。
030243mb5adkdtlllklz56.gif

API
Animation C# Jobs由Playable API提供支持。它带来了三个新结构:AnimationScriptPlayable、IAnimationJob和AnimationStream。

AnimationScriptPlayable和IAnimationJob
AnimationScriptPlayable是一个全新的动画Playable,和Playable一样,它可以添加到PlayableGraph的任何位置。它包含一个动画作业,能够作为PlayableGraph和作业之间的代理。该作业是个实现IAnimationJob的用户定义结构。

Playable的常见作业流程会输入动画流并混合流中的结果。该动画流程分为二个通道,每个通道都自带IPlayableJob中的回调函数:
ProcessRootMotion会处理Root Transform的动作,它会在ProcessAnimation前调用,并根据Animator剔除模式确定是否调用ProcessAnimation。 ProcessAnimation用于除Root Motion根动画外的所有对象。

下面示例是一个非常基础的Animation C# Jobs。它会帮助我们了解如何使用动画作业创建AnimationScriptPlayable。
[C#] 纯文本查看 复制代码using UnityEngine; using UnityEngine.Playables; using UnityEngine.Animations; using UnityEngine.Experimental.Animations; public struct AnimationJob : IAnimationJob { public void ProcessRootMotion(AnimationStream stream) { } public void ProcessAnimation(AnimationStream stream) { } } [RequireComponent(typeof(Animator))] public class AnimationScriptExample : MonoBehaviour { PlayableGraph m_Graph; AnimationScriptPlayable m_ScriptPlayable; void OnEnable() { // 创建视图 m_Graph = PlayableGraph.Create(AnimationScriptExample); // 创建Animation job和Playable var animationJob = new AnimationJob(); m_ScriptPlayable = AnimationScriptPlayable.Create(m_Graph, animationJob); // 创建输出结果并将结果链接到Playable上 var output = AnimationPlayableOutput.Create(m_Graph, Output, GetComponent<Animator>()); output.SetSourcePlayable(m_ScriptPlayable); } void OnDisable() { m_Graph.Destroy(); } }
作为IAnimationJob方法的参数传递的流,它是在每个处理通道中将要处理的对象。

默认情况下,所有AnimationScriptPlayable输入会被处理。在仅有一个输入即后期处理作业的情况下,该流会包含已处理输入的结果。在有多个输入即混合作业的情况下,最好是手动处理输入。

为了实现手动处理,AnimationScriptPlayable.SetProcessInputs(bool)将启用或禁用输入的处理通道。为了触发输入的处理过程并获取手动模式中的结果流,请调用AnimationStream.GetInputStream()。

AnimationStream和句柄
通过AnimationStream,开发者可以访问视图中Playable之间流动的数据。它还可以访问由Animator组件设置动画的所有数值。
[C#] 纯文本查看 复制代码public struct AnimationStream { public bool isValid { get ; } public float deltaTime { get ; } public Vector3 velocity { get ; set ; } public Vector3 angularVelocity { get ; set ; } public Vector3 rootMotionPosition { get ; } public Quaternion rootMotionRotation { get ; } public bool isHumanStream { get ; } public AnimationHumanStream AsHuman ( ) ; public int inputStreamCount { get ; } public AnimationStream GetInputStream ( int index ) ; }
由于同样的数据可能在流的帧与帧之间处于不同的偏移,所以无法直接访问流数据。例如:通过在视图中添加或移除AnimationClip,该数据或许已经移动或是不存在于流中。

为了确保这些访问的安全性和有效性,我们引入了二组句柄:流句柄和场景句柄,其中每个句柄都带有变换和组件属性句柄。

1、流句柄
流句柄(Stream Handle)会安全地管理所有对AnimationStream数据的所有访问。如果发生错误,该系统会抛出C#异常。流句柄共有二个类型:TransformStreamHandle和PropertyStreamHandle。

TransformStreamHandle管理Transform并处理变换层级。这意味着你可以修改流中的本地或全局Transform位置,并且为以后位置的请求将提供可预测的结果。

PropertyStreamHandle管理系统可以在组件上设置动画和查找的所有属性。例如:它可以用于读取或写入Light.m_Intensity属性的数值。

[C#] 纯文本查看 复制代码public struct TransformStreamHandle { public bool IsValid(AnimationStream stream); public bool IsResolved(AnimationStream stream); public void Resolve(AnimationStream stream); public void SetLocalPosition(AnimationStream stream, Vector3 position); public Vector3 GetLocalPosition(AnimationStream stream); public void SetLocalRotation(AnimationStream stream, Quaternion rotation); public Quaternion GetLocalRotation(AnimationStream stream); public void SetLocalScale(AnimationStream stream, Vector3 scale); public Vector3 GetLocalScale(AnimationStream stream); public void SetPosition(AnimationStream stream, Vector3 position); public Vector3 GetPosition(AnimationStream stream); public void SetRotation(AnimationStream stream, Quaternion rotation); public Quaternion GetRotation(AnimationStream stream); } public struct PropertyStreamHandle { public bool IsValid(AnimationStream stream); public bool IsResolved(AnimationStream stream); public void Resolve(AnimationStream stream); public void SetFloat(AnimationStream stream, float value); public float GetFloat(AnimationStream stream); public void SetInt(AnimationStream stream, int value); public int GetInt(AnimationStream stream); public void SetBool(AnimationStream stream, bool value); public bool GetBool(AnimationStream stream); }
2、场景句柄
场景句柄(Scene Handle)是安全访问任意数值的另一种形式,但是它来自场景而不是AnimationStream。对于流句柄而言,有二种场景句柄:TransformSceneHandle和PropertySceneHandle。

场景句柄的一个具体用法是对Foot IK实现效应器(Effector)。IK效应器通常是未经过Animator设置动画的游戏对象,因此它在Transform外部由PlayableGraph中的动画剪辑修改。该作业需要获取IK效应器的全局位置,从而计算足部的合适位置。因此IK效应器要通过场景句柄访问,同时流句柄将用于处理腿部骨骼。
[C#] 纯文本查看 复制代码public struct TransformSceneHandle { public bool IsValid(AnimationStream stream); public void SetLocalPosition(AnimationStream stream, Vector3 position); public Vector3 GetLocalPosition(AnimationStream stream); public void SetLocalRotation(AnimationStream stream, Quaternion rotation); public Quaternion GetLocalRotation(AnimationStream stream); public void SetLocalScale(AnimationStream stream, Vector3 scale); public Vector3 GetLocalScale(AnimationStream stream); public void SetPosition(AnimationStream stream, Vector3 position); public Vector3 GetPosition(AnimationStream stream); public void SetRotation(AnimationStream stream, Quaternion rotation); public Quaternion GetRotation(AnimationStream stream); } public struct PropertySceneHandle { public bool IsValid(AnimationStream stream); public bool IsResolved(AnimationStream stream); public void Resolve(AnimationStream stream); public void SetFloat(AnimationStream stream, float value); public float GetFloat(AnimationStream stream); public void SetInt(AnimationStream stream, int value); public int GetInt(AnimationStream stream); public void SetBool(AnimationStream stream, bool value); public bool GetBool(AnimationStream stream); }
AnimationJobExtensions
最后一部分是AnimationJobExtension类,它是作用所有功能的“粘合器”。它使Animator得到扩展,从而创建出上述的句柄。

AnimationJobExtension共有四个方法:BindStreamTransform、BindStreamProperty、BindSceneTransform和BindSceneProperty。

[C#] 纯文本查看 复制代码public static class AnimatorJobExtensions { public static TransformStreamHandle BindStreamTransform(this Animator animator, Transform transform); public static PropertyStreamHandle BindStreamProperty(this Animator animator, Transform transform, Type type, string property); public static TransformSceneHandle BindSceneTransform(this Animator animator, Transform transform); public static PropertySceneHandle BindSceneProperty(this Animator animator, Transform transform, Type type, string property); }
BindStream方法可用于在已设置动画的属性上创建句柄,或是为流中新设置动画的属性创建句柄。

参考资料
下面是一些参考的API文档,请访问Unity在线手册,输入相应关键字进行查看。
AnimationScriptPlayable IAnimationJob AnimationScript TransformStreamHandle PropertyStreamHandle TransformSceneHandle PropertySceneHandle


小结
关于Animation C# Jobs就介绍到这里了,如果你遇到错误,请使用Unity中的Bug Reporter来报告错误。

有关此实验性功能的任何反馈,请访问Unity官方英文论坛帖子提出:
https://forum.unity.com/threads/ ... in-2018-2a5.525012/

更多Unity的技术资料尽在Unity官方中文论坛(UnityChina.cn)!
Job System, 动画 本主题由 admin 于 3天前 置顶锐亚教育

锐亚教育 锐亚科技 unity unity教程