Unity实用案例之——动画压缩

关于动画文件的压缩,其实前辈们已经讲得非常详尽了:
http://www.codershu.com/2017/06/14/UnityOptimizeAnimationClip/
http://gad.qq.com/article/detail/15869
写这篇文章一是为了弥补原文已失效的附件,二是为了更新已过时的API。
不多说,直接上代码:

这里只介绍两种压缩方案:

删减帧:

private static void ReduceScaleKey(AnimationClip clip, string keyName) 
{
    EditorCurveBinding[] curves = AnimationUtility.GetCurveBindings(clip);

    for (int j = 0; j < curves.Length; j++) {
        EditorCurveBinding curveBinding = curves[j];

        if (curveBinding.propertyName.ToLower().Contains(keyName)) {
            AnimationUtility.SetEditorCurve(clip, curveBinding, null);
        }
    }
}

动画精度压缩:

private static void ReduceFloatPrecision(AnimationClip clip)
{
    EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip);

    for (int j = 0; j < bindings.Length; j++)
    {
        EditorCurveBinding curveBinding = bindings[j];
        AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, curveBinding);

        if (curve == null || curve.keys == null)
        {
            continue;
        }

        Keyframe[] keys = curve.keys;
        for (int k = 0; k < keys.Length; k++)
        {
            Keyframe key = keys[k];
            key.value = float.Parse(key.value.ToString("f3"));
            key.inTangent = float.Parse(key.inTangent.ToString("f3"));
            key.outTangent = float.Parse(key.outTangent.ToString("f3"));
            keys[k] = key;
        }
        curve.keys = keys;

        AnimationUtility.SetEditorCurve(clip, curveBinding, curve);
    }
}

提供两种压缩选择:

1.导入时压缩动画:

public class AnimCompress : AssetPostprocessor
{
    public const string ScaleKeyName = "localscale";
    public const string RotationKeyName = "localrotation";

    void OnPostprocessModel(GameObject go)
    {
        List<AnimationClip> clips = new List<AnimationClip>(AnimationUtility.GetAnimationClips(go));

        if (clips.Count == 0) {
            AnimationClip[] objectList = Object.FindObjectsOfType(typeof(AnimationClip)) as AnimationClip[];
            if (objectList != null)
            {
                clips.AddRange(objectList);
            }
        }

        for (int i = 0; i < clips.Count; i++)
        {
            CompressAnim(clips[i]);
        }
    }

    public static void CompressAnim(AnimationClip clip)
    {
        ReduceScaleKey(clip, ScaleKeyName);
        ReduceFloatPrecision(clip);
    }
}

但是由于动画文件在改动后会恢复原始大小,所以增加另一种方案

2.压缩选择的动画文件:

[MenuItem("Tools/Animation/CompressAnim &v")]
public static void CompressAnimMenu()
{
    try
    {
        var selectGos = Selection.gameObjects;
        for (int i = 0; i < selectGos.Length; i++)
        {
            EditorUtility.DisplayProgressBar("CompressAnim", selectGos[i].name + " Compressing...", ((float)i / selectGos.Length));
            AnimationClip[] clips = GetAnimationClips(selectGos[i]);
            foreach (var c in clips) {
                CompressAnim(c);
            }
        }
    }
    catch (Exception)
    {
        EditorUtility.ClearProgressBar();
        throw;
    }
    EditorUtility.ClearProgressBar();
}

/// <summary>
/// 获取GameObject上的AnimationClips
/// </summary>
public static AnimationClip[] GetAnimationClips(GameObject go)
{
    List<AnimationClip> clips = new List<AnimationClip>();

    string path = AssetDatabase.GetAssetPath(go);
    Object[] objects = AssetDatabase.LoadAllAssetsAtPath(path);

    foreach (var o in objects) {
        if (o is AnimationClip) {
            clips.Add((AnimationClip)o);
        }
    }

    return clips.ToArray();
}

这样我们就可以先设置好动画文件的参数以及其他准备工作,最后再压缩就好了

这里写图片描述
这里写图片描述
本文采用了两种效率最高的压缩方案,惊奇的是,在Editor下测试的结果,一个动画从284k压到到50k,最高压缩率接近82%!虽然不是真机测试结果,但足以说明动画文件优化的提升空间有多大。
小伙伴儿门赶紧在自己的项目中测试一下吧!

猜你喜欢

转载自blog.csdn.net/u013917120/article/details/79824448