随着Unity 2017.1发布,备受期待的Timeline工具也正式与大家见面,并带来了最大的功能亮点Playable API。今天这篇文章,将为大家介绍Playable API的概念与应用示例,以及未来即将推出的新功能。

图形化的Playable API支持对动画及音频进行精确的编程控制,我们也正在探索Playable API对视频控制的支持。Unity 2017.1中全新的Timeline工具就用到了Playable API。

Playable API为动画提供了之前使用Animator无法实现的控制级别,Playable API支持以下功能:

直接在Animator上播放AnimationClip,不需要使用AnimatorController(动画)
直接控制正在播放的每个独立AnimationClip的时间与权重
运行时在Playable API图中动态添加AnimationClip
混用AnimatorController与AnimationClips,动画甚至是Timeline

我们曾经分享过Playable API的相关文章,请查阅《Playable API:动画和视频进入新阶段》。

为了便于开发者创建并调试Playable API,我们创建了PlayableGraph可视化工具。该工具支持在运行模式及编辑器模式下显示任意PlayableGraph,并持续反应图中的当前状态。图中的Playable以带颜色的节点表示,不同类型的Playable颜色也不同。线的颜色与强度则表示该Playable在混合中所占的权重。

请访问GitHub下载PlayableGraph可视化工具。

温馨提示,Unity 2017.1中的Playable API相较Unity 5.6中有了一些改动,请查阅文档了解详情。

关于Playable API比较有趣的是,所有Unity“原生”提供的Playable都使用C#结构体而非C++对象来保存对象。使用结构体的优点是无需分配GC所需的内存。这样用起来可能稍微有点复杂,但由于该API承载了未来的很多功能,所以必须注重性能问题。

现在开发者可以基于Playable来实现自定义系统。例如,对于那些仍倾向于使用旧版动画系统的开发者,可以通过Playable API实现一个前端API,使用Mecanim来模仿旧版动画系统的行为。该功能即将发布并更新到GitHub中,可以先看看下面的视频来了解该功能:

http://v.qq.com/x/page/u053565moy1.html

有了该功能,就可以利用多线程与可重定向动画引擎像旧版动画系统那样控制动画。

PlayableBehaviour
在Playable API仍处于实验阶段时,我们推出了ScriptPlayable,它既是Playable节点的容器,也是自定义节点的内容。后来我们将它拆分为两部分,现在的ScriptPlayable仅作为容器,而PlayableBehaviour则是节点的内容。

Playable API支持创建继承自PlayableBehaviour的自定义Playable。重写“PrepareFrame”方法就可以按自定义方式处理节点。自定义Playable也可以基于需要处理的事件,重写PlayableBehaviour的任意虚方法。

例如,最基础的自定义Playable如下:

[C#] 纯文本查看 复制代码public class MyNicePlayableBehaviour : PlayableBehaviour { override public void PrepareFrame(Playable owner, FrameData info) { } }

创建Playable代码如下:

[C#] 纯文本查看 复制代码var nicePlayable = ScriptPlayable<MyNicePlayableBehaviour>.Create(playableGraph);

这与之前版本的Playable不同,但这种方式更加符合Playable API未来的计划。

Playable API未来计划

在Unite Europe 2017的Keynote主题演讲中,Unity CTO – Joachim Ante带来了关于C#计算任务的演示。请查看下方视频了解详情(可直接跳转至1:07:33秒):

http://v.qq.com/x/page/i0519p6m4tu.html

我们正在着手将AnimationPlayables融入C#任务系统。这将支持让开发者在高度优化、支持多线程及线程安全的C#代码中直接控制动画流值(如Transform、浮点数、肌肉等)。开发者创建的C#动画任务可以连接到PlayableGraph,并且支持基于关节约束来创建自定义PlayableGraph。使用C#编写的代在多线程动画系统中运行,并在遍历PlayableGraph时进行评估。

下面来看一个简短的示例,如何实现非常简单的FullBodyIK(全身反向动力学)算法。

210603ltkdkpv1v75pk6tv.gif

[C#] 纯文本查看 复制代码public struct FullBodyIKJob : IProcessAnimationJob { public TransformSceneHandle leftFootEffector; public TransformSceneHandle rightFootEffector; public TransformSceneHandle leftHandEffector; public TransformSceneHandle rightHandEffector; public void ProcessAnimation(AnimationStream stream) { FullBodyIK.IKGoal [] goals = new FullBodyIK.IKGoal [4]; FullBodyIK.GetGoals(stream, goals); if (stream.IsValid(leftFootEffector)) { goals[(int)AvatarIKGoal.LeftFoot].position = stream.GetPosition(leftFootEffector); goals[(int)AvatarIKGoal.LeftFoot].rotation = stream.GetRotation(leftFootEffector); goals[(int)AvatarIKGoal.LeftFoot].positionWeight = 1.0f; } // do for each effector. if (stream.IsValid(RightFootEffector)) ///... FullBodyIK.Solve(stream, goals); } } public static void Solve(AnimationStream stream, IKGoal[] goals) { var human = stream.human; human.bodyRotation = new float4(0, 0, 0, 1);; float3 bodyPosition = human.bodyPosition; float3 bodyPositionDelta = new float3(0, 0, 0); float sumWeight = 0; // pull engine for (int goalIter = 0; goalIter < 4; goalIter++) { bodyPositionDelta += (goals[goalIter].position - stream.human.GetGoalPositionFromPose((AvatarIKGoal)goalIter)) * goals[goalIter].positionWeight; sumWeight += goals[goalIter].positionWeight; } if (sumWeight > 1) { bodyPositionDelta /= sumWeight; } human.bodyPosition = bodyPosition + bodyPositionDelta; SetGoals(stream, goals); stream.human.IKSolve (); }

安装与实例化Playable代码如下:

[C#] 纯文本查看 复制代码ikPlayable = AnimationScriptPlayableJob<FullBodyIKJob>.Create(); var fullBodyIK = new FullBodyIKJob(); fullBodyIK.leftFootEffector = player.BindSceneTransform(leftFootEffector); fullBodyIK.rightFootEffector = player.BindSceneTransform(rightFootEffector); fullBodyIK.leftHandEffector = player.BindSceneTransform(leftHandEffector); fullBodyIK.rightHandEffector = player.BindSceneTransform(rightHandEffector); ikPlayable.SetJobData (fullBodyIK);

注意,以上示例代码仍是早期原型阶段,后面可能会改动。

除了上面的示例外,我们还提供了以下用例的原型:

CustomMixer:支持在混合过程中为每个Transform指定不同权重
IKSolver:自定义IK解决方案,目前为二骨骼,支持Google的CCD算法或
MotionStream:支持直接播放姿势(而非动画)的特殊节点
LiveMocap:支持读取动捕数据并写入AnimationStream
KneePoppingFixer:当身体部位接近完全展开时可以添加缩放

以上都是可以利用C# AnimationPlayables实现的非常好的用例,我们也迫切希望可以将这些用例尽快发布供大家使用。我们会不断更新,请大家保持关注。



Unity, 2017, Timeline, Playable, API锐亚教育

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