4.如何获取某个目标对象的动画信息
4.1 知识点
整段 VAT 流水线都在 Editor 里跑,读 AnimatorController 要用 UnityEditor.Animations。这一节只负责把「角色身上到底有哪些 AnimationClip」列出来;从 layers[0].stateMachine.states 拿到的 childAnimatorStateArray,后面第 5、6 篇会原样接着用,不必改字段名。
为何要获取某个目标对象的动画信息
- 第一个目的是要生成
VAT。 VAT中存储的就是对象动画的每帧顶点位置信息。- 因此首先要做的,就是获取目标对象的动画信息。
获取某个目标对象的动画信息
主要目的
- 获取某个对象所使用到的全部
AnimationClip信息。 - 这样就能得到所有动画的关键信息(例如帧率、时长等)。
主要思路
Animator上挂着RuntimeAnimatorController,强转成AnimatorController之后可以读到各层状态机。- 状态上的
motion经常是AnimationClip(也可能是BlendTree等,那种要另写分支,这里按单 Clip 处理)。
主要步骤
- 得到目标
GameObject。 - 得到该
GameObject上的Animator组件。 - 通过
Animator得到AnimatorController(runtimeAnimatorController强转为AnimatorController);若为null则结束。 - 从
AnimatorController中取对应层(示例为layers[0])的状态机AnimatorStateMachine。 - 从状态机中取出所有状态,得到
ChildAnimatorState[]。 - 遍历该数组:每个状态上的
motion转成AnimationClip后,可读frameRate、length,并用Mathf.CeilToInt(animationClip.frameRate * animationClip.length)算出该Clip大约多少帧。
对应步骤的代码如下(与文末 4.2 逻辑一致,这里未写 animationClip 判空,复制到工程里时建议补上):
using UnityEngine;
using UnityEditor.Animations;
//1.得到目标GameObject
//2.得到GameObject上的Animator组件
Animator animator = targetGameObject.GetComponent<Animator>();
//3.通过Animator组件得到AnimatorController
AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController;
if (animatorController == null)
{
return;
}
//4.得到AnimatorController中对应层的状态机AnimatorStateMachine
AnimatorStateMachine animatorStateMachine = animatorController.layers[0].stateMachine;
//5.得到状态机中的所有状态ChildAnimatorState[]数组
ChildAnimatorState[] childAnimatorStateArray = animatorStateMachine.states;
//之所以绕一圈去获取动画切片 是为了之后做铺垫
//我们可以结合Animator,蒙皮网格渲染器,利用他们一起去得到某一个动画某一帧对应的顶点数据
//6.遍历该数组
// 其中每个状态的motion就是对应的动画切片AnimationClip
// 这样我们就能得到帧率、时长等关键信息
for (int i = 0; i < childAnimatorStateArray.Length; i++)
{
AnimatorState animatorState = childAnimatorStateArray[i].state;
AnimationClip animationClip = animatorState.motion as AnimationClip;
// animationClip.frameRate 帧率
// animationClip.length 时长
int frameCount = Mathf.CeilToInt(animationClip.frameRate * animationClip.length);//得到这个clip多少帧
}
先拿到 AnimationClip,后面才能用 SampleAnimation 定帧、用 SkinnedMeshRenderer.BakeMesh 把蒙皮结果落成网格顶点,这一环在第 5 篇接。
4.2 知识点代码
GetTargetAnimationInfoExample.cs
using UnityEngine;
using UnityEditor.Animations;
// 将本脚本放在项目的 Editor 目录下,并确保程序集引用了 UnityEditor
public static class GetTargetAnimationInfoExample
{
public static void ExampleInspect(GameObject targetGameObject)
{
if (targetGameObject == null)
{
return;
}
//我们的第一个目的是要生成VAT
//VAT中存储的就是对象动画的每帧顶点位置信息
//因此我们首先要做的就是获取目标对象的动画信息
//主要目的:
//获取某个对象的所有使用的AnimationClip信息
//这样就能得到所有动画的关键信息
//主要思路:
//通过获取Animator动画状态机中的状态
//从而得到动画信息,因为状态的本质就是动画
//主要步骤:
//1.得到目标GameObject
//2.得到GameObject上的Animator组件
Animator animator = targetGameObject.GetComponent<Animator>();
if (animator == null)
{
return;
}
//3.通过Animator组件得到AnimatorController
AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController;
if (animatorController == null)
{
return;
}
//4.得到AnimatorController中对应层的状态机AnimatorStateMachine
AnimatorStateMachine animatorStateMachine = animatorController.layers[0].stateMachine;
//5.得到状态机中的所有状态ChildAnimatorState[]数组
ChildAnimatorState[] childAnimatorStateArray = animatorStateMachine.states;
//6.遍历该数组
// 其中每个状态的motion就是对应的动画切片AnimationClip
// 这样我们就能得到帧率、时长等关键信息
for (int i = 0; i < childAnimatorStateArray.Length; i++)
{
AnimatorState animatorState = childAnimatorStateArray[i].state;
AnimationClip animationClip = animatorState.motion as AnimationClip;
if (animationClip == null)
{
continue;
}
// animationClip.frameRate 帧率
// animationClip.length 时长
int frameCount = Mathf.CeilToInt(animationClip.frameRate * animationClip.length);//得到这个clip多少帧
}
//之所以绕一圈去获取动画切片 是为了之后做铺垫
//我们可以结合Animator,蒙皮网格渲染器,利用他们一起去得到某一个动画某一帧对应的顶点数据
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com