unity3d动画系统的动画曲线描绘

2015年01月23日 11:10 0 点赞 0 评论 更新于 2025-11-21 15:10

在网上我发现了一篇关于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;
}
}

代码解释

  1. 变量定义
    • Interpolations:用于定义曲线中采样点的数量,采样点越多,绘制的曲线越精确。
  2. OnDrawGizmos 方法
    • 该方法会在场景视图中绘制Gizmos,用于可视化动画路径。
    • 首先检查 Interpolations 是否大于0,若不满足则不进行绘制。
    • 通过 AnimationUtility.GetAnimationClips 方法获取GameObject上的所有动画剪辑。
    • 遍历每个动画剪辑,为每个剪辑计算动画曲线的最大时间 TotalTime,并获取 xyz 三个方向的动画曲线。
    • 若某个动画剪辑没有位移相关的动画曲线,则输出警告信息并跳过该剪辑。
    • 根据最大时间和采样点数量计算时间间隔 interval,并在每个时间点上计算物体的位置。
    • 若物体有父物体,则将局部位置转换为世界位置。
    • 最后使用 Gizmos.DrawLine 方法连接相邻的采样点,绘制出动画路径。
  3. GetMaxTime 方法
    • 该方法用于获取动画曲线的最大时间,通过遍历曲线的所有关键帧,比较每个关键帧的时间,返回最大时间。

使用方法

将上述脚本保存为 .cs 文件,然后将其挂载到带有动画的GameObject上,在场景视图中即可看到动画运行时的路径。

作者信息

feifeila

feifeila

共发布了 3994 篇文章