unity3d动画系统的动画曲线描绘
在网上我发现了一篇关于Unity3D动画系统动画曲线描绘的文章,虽内容简洁,但实用性颇高,在此分享给大家。
在Unity3D里,当编辑Transform动画曲线时,无法直接看到GameObject的运动路线。为此,我编写了一个脚本,将其挂载到带有动画的GameObject上,就能显示运行动画时的路线。
脚本效果
该脚本可以在场景视图中绘制出GameObject在动画运行时的运动路径,以红色曲线展示,方便开发者直观查看动画的运动轨迹。
脚本代码
using UnityEngine;
using UnityEditor;
using System.Collections;
public class AnimationGizmos : MonoBehaviour {
// 曲线中的点数量
public int Interpolations = 32;
// 绘制路径曲线
void OnDrawGizmos() {
if (Interpolations > 0) {
Gizmos.color = Color.red;
// 获取所有的动画曲线
AnimationClip[] clips = AnimationUtility.GetAnimationClips(gameObject);
if (clips.Length == 0) {
return;
}
for (int curveIndex = 0; curveIndex < clips.Length; curveIndex++) {
Vector3[] points = new Vector3[Interpolations + 1];
AnimationCurve curveX = null;
AnimationCurve curveY = null;
AnimationCurve curveZ = null;
float TotalTime = 0;
bool curveReady = false;
AnimationClip clip = clips[curveIndex];
AnimationClipCurveData[] curveDatas = AnimationUtility.GetAllCurves(clip, true);
foreach (AnimationClipCurveData curveData in curveDatas) {
if ("m_LocalPosition.x" == curveData.propertyName) {
curveX = curveData.curve;
TotalTime = GetMaxTime(curveData.curve, TotalTime);
curveReady = true;
} else if ("m_LocalPosition.y" == curveData.propertyName) {
curveY = curveData.curve;
TotalTime = GetMaxTime(curveData.curve, TotalTime);
curveReady = true;
} else if ("m_LocalPosition.z" == curveData.propertyName) {
curveZ = curveData.curve;
TotalTime = GetMaxTime(curveData.curve, TotalTime);
curveReady = true;
}
}
if (!curveReady) {
Debug.LogWarning(clip.name + " 动画无位移");
continue;
}
float interval = TotalTime / Interpolations;
for (int i = 0; i <= Interpolations; i++) {
float time = i * interval;
Vector3 pos = transform.localPosition;
if (curveX != null) {
pos.x = curveX.Evaluate(time);
}
if (curveY != null) {
pos.y = curveY.Evaluate(time);
}
if (curveZ != null) {
pos.z = curveZ.Evaluate(time);
}
if (transform.parent != null) {
pos = transform.parent.TransformPoint(pos);
}
points[i] = pos;
}
for (int i = 0; i < Interpolations; i++) {
Gizmos.DrawLine(points[i], points[i + 1]);
}
}
}
}
private static float GetMaxTime(AnimationCurve curveX, float TotalTime) {
foreach (Keyframe keyframe in curveX.keys) {
if (keyframe.time > TotalTime) {
TotalTime = keyframe.time;
}
}
return TotalTime;
}
}
代码解释
- 变量定义:
Interpolations:用于定义曲线中采样点的数量,采样点越多,绘制的曲线越精确。
OnDrawGizmos方法:- 该方法会在场景视图中绘制Gizmos,用于可视化动画路径。
- 首先检查
Interpolations是否大于0,若不满足则不进行绘制。 - 通过
AnimationUtility.GetAnimationClips方法获取GameObject上的所有动画剪辑。 - 遍历每个动画剪辑,为每个剪辑计算动画曲线的最大时间
TotalTime,并获取x、y、z三个方向的动画曲线。 - 若某个动画剪辑没有位移相关的动画曲线,则输出警告信息并跳过该剪辑。
- 根据最大时间和采样点数量计算时间间隔
interval,并在每个时间点上计算物体的位置。 - 若物体有父物体,则将局部位置转换为世界位置。
- 最后使用
Gizmos.DrawLine方法连接相邻的采样点,绘制出动画路径。
GetMaxTime方法:- 该方法用于获取动画曲线的最大时间,通过遍历曲线的所有关键帧,比较每个关键帧的时间,返回最大时间。
使用方法
将上述脚本保存为 .cs 文件,然后将其挂载到带有动画的GameObject上,在场景视图中即可看到动画运行时的路径。