游戏开发中的坑之五 动画文件大小压缩

参考http://www.codershu.com/2017/06/14/UnityOptimizeAnimationClip/

网上有许多脚本,思路都是一样的,但是菜鸟我用的时候会报各种错误,只有这个脚本只有一个报错,感觉似乎能解决,

然后在原脚本上添加了一句using UnityEngine.Profiling; OK!没报错了!

主要思路

1.压缩浮点数精度

2.去除scale曲线

FBX的Animations设置中,Anim.Compression :Keyframe Reduction;

如果设置为Keyframe Reduction and Compression 确实也会减少文件大小,但是可能出现动作衔接抖动问题。

代码如下

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using UnityEditor;
using System.IO;
using UnityEngine.Profiling;

namespace EditorTool
{
    class AnimationOpt
    {
        static Dictionary<uint, string> _FLOAT_FORMAT;
        static MethodInfo getAnimationClipStats;
        static FieldInfo sizeInfo;
        static object[] _param = new object[1];

        static AnimationOpt()
        {
            _FLOAT_FORMAT = new Dictionary<uint, string>();
            for (uint i = 1; i < 6; i++)
            {
                _FLOAT_FORMAT.Add(i, "f" + i.ToString());
            }
            Assembly asm = Assembly.GetAssembly(typeof(Editor));
            getAnimationClipStats = typeof(AnimationUtility).GetMethod("GetAnimationClipStats", BindingFlags.Static | BindingFlags.NonPublic);
            Type aniclipstats = asm.GetType("UnityEditor.AnimationClipStats");
            sizeInfo = aniclipstats.GetField("size", BindingFlags.Public | BindingFlags.Instance);
        }

        AnimationClip _clip;
        string _path;

        public string path { get { return _path; } }

        public long originFileSize { get; private set; }

        public int originMemorySize { get; private set; }

        public int originInspectorSize { get; private set; }

        public long optFileSize { get; private set; }

        public int optMemorySize { get; private set; }

        public int optInspectorSize { get; private set; }

        public AnimationOpt(string path, AnimationClip clip)
        {
            _path = path;
            _clip = clip;
            _GetOriginSize();
        }

        void _GetOriginSize()
        {
            originFileSize = _GetFileZie();
            originMemorySize = _GetMemSize();
            originInspectorSize = _GetInspectorSize();
        }

        void _GetOptSize()
        {
            optFileSize = _GetFileZie();
            optMemorySize = _GetMemSize();
            optInspectorSize = _GetInspectorSize();
        }

        long _GetFileZie()
        {
            FileInfo fi = new FileInfo(_path);
            return fi.Length;
        }

        int _GetMemSize()
        {
            return Profiler.GetRuntimeMemorySize(_clip);
        }

        int _GetInspectorSize()
        {
            _param[0] = _clip;
            var stats = getAnimationClipStats.Invoke(null, _param);
            return (int)sizeInfo.GetValue(stats);
        }

        void _OptmizeAnimationScaleCurve()
        {
            if (_clip != null)
            {
                //去除scale曲线
                foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(_clip))
                {
                    string name = theCurveBinding.propertyName.ToLower();
                    if (name.Contains("scale"))
                    {
                        AnimationUtility.SetEditorCurve(_clip, theCurveBinding, null);
                        Debug.LogFormat("关闭{0}的scale curve", _clip.name);
                    }
                }
            }
        }

        void _OptmizeAnimationFloat_X(uint x)
        {
            if (_clip != null && x > 0)
            {
                //浮点数精度压缩到f3
                AnimationClipCurveData[] curves = null;
                curves = AnimationUtility.GetAllCurves(_clip);
                Keyframe key;
                Keyframe[] keyFrames;
                string floatFormat;
                if (_FLOAT_FORMAT.TryGetValue(x, out floatFormat))
                {
                    if (curves != null && curves.Length > 0)
                    {
                        for (int ii = 0; ii < curves.Length; ++ii)
                        {
                            AnimationClipCurveData curveDate = curves[ii];
                            if (curveDate.curve == null || curveDate.curve.keys == null)
                            {
                                //Debug.LogWarning(string.Format("AnimationClipCurveData {0} don't have curve; Animation name {1} ", curveDate, animationPath));
                                continue;
                            }
                            keyFrames = curveDate.curve.keys;
                            for (int i = 0; i < keyFrames.Length; i++)
                            {
                                key = keyFrames[i];
                                key.value = float.Parse(key.value.ToString(floatFormat));
                                key.inTangent = float.Parse(key.inTangent.ToString(floatFormat));
                                key.outTangent = float.Parse(key.outTangent.ToString(floatFormat));
                                keyFrames[i] = key;
                            }
                            curveDate.curve.keys = keyFrames;
                            _clip.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);
                        }
                    }
                }
                else
                {
                    Debug.LogErrorFormat("目前不支持{0}位浮点", x);
                }
            }
        }

        public void Optimize(bool scaleOpt, uint floatSize)
        {
            if (scaleOpt)
            {
                _OptmizeAnimationScaleCurve();
            }
            _OptmizeAnimationFloat_X(floatSize);
            _GetOptSize();
        }

        public void Optimize_Scale_Float3()
        {
            Optimize(true, 3);
        }

        public void LogOrigin()
        {
            _logSize(originFileSize, originMemorySize, originInspectorSize);
        }

        public void LogOpt()
        {
            _logSize(optFileSize, optMemorySize, optInspectorSize);
        }

        public void LogDelta()
        {

        }

        void _logSize(long fileSize, int memSize, int inspectorSize)
        {
            Debug.LogFormat("{0} \nSize=[ {1} ]", _path, string.Format("FSize={0} ; Mem->{1} ; inspector->{2}",
                EditorUtility.FormatBytes(fileSize), EditorUtility.FormatBytes(memSize), EditorUtility.FormatBytes(inspectorSize)));
        }
    }

    public class OptimizeAnimationClipTool
    {
        static List<AnimationOpt> _AnimOptList = new List<AnimationOpt>();
        static List<string> _Errors = new List<string>();
        static int _Index = 0;

        [MenuItem("Assets/Animation/裁剪浮点数去除Scale")]
        public static void Optimize()
        {
            _AnimOptList = FindAnims();
            if (_AnimOptList.Count > 0)
            {
                _Index = 0;
                _Errors.Clear();
                EditorApplication.update = ScanAnimationClip;
            }
        }

        private static void ScanAnimationClip()
        {
            AnimationOpt _AnimOpt = _AnimOptList[_Index];
            bool isCancel = EditorUtility.DisplayCancelableProgressBar("优化AnimationClip", _AnimOpt.path, (float)_Index / (float)_AnimOptList.Count);
            _AnimOpt.Optimize_Scale_Float3();
            _Index++;
            if (isCancel || _Index >= _AnimOptList.Count)
            {
                EditorUtility.ClearProgressBar();
                Debug.Log(string.Format("--优化完成--    错误数量: {0}    总数量: {1}/{2}    错误信息↓:\n{3}\n----------输出完毕----------", _Errors.Count, _Index, _AnimOptList.Count, string.Join(string.Empty, _Errors.ToArray())));
                Resources.UnloadUnusedAssets();
                GC.Collect();
                AssetDatabase.SaveAssets();
                EditorApplication.update = null;
                _AnimOptList.Clear();
                _cachedOpts.Clear();
                _Index = 0;
            }
        }

        static Dictionary<string, AnimationOpt> _cachedOpts = new Dictionary<string, AnimationOpt>();

        static AnimationOpt _GetNewAOpt(string path)
        {
            AnimationOpt opt = null;
            if (!_cachedOpts.ContainsKey(path))
            {
                AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(path);
                if (clip != null)
                {
                    opt = new AnimationOpt(path, clip);
                    _cachedOpts[path] = opt;
                }
            }
            return opt;
        }

        static List<AnimationOpt> FindAnims()
        {
            string[] guids = null;
            List<string> path = new List<string>();
            List<AnimationOpt> assets = new List<AnimationOpt>();
            UnityEngine.Object[] objs = Selection.GetFiltered(typeof(object), SelectionMode.Assets);
            if (objs.Length > 0)
            {
                for (int i = 0; i < objs.Length; i++)
                {
                    if (objs[i].GetType() == typeof(AnimationClip))
                    {
                        string p = AssetDatabase.GetAssetPath(objs[i]);
                        AnimationOpt animopt = _GetNewAOpt(p);
                        if (animopt != null)
                            assets.Add(animopt);
                    }
                    else
                        path.Add(AssetDatabase.GetAssetPath(objs[i]));
                }
                guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(AnimationClip).ToString().Replace("UnityEngine.", "")), path.ToArray());
            }
            else
            {
                guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(AnimationClip).ToString().Replace("UnityEngine.", "")));
            }
            for (int i = 0; i < guids.Length; i++)
            {
                string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
                AnimationOpt animopt = _GetNewAOpt(assetPath);
                if (animopt != null)
                    assets.Add(animopt);
            }
            return assets;
        }
    }
}

道理上点击需要压缩的文件,右键,Animation,裁剪浮点数去除Scale

实际上似乎把所有动作文件都进行修改了,并且有一个报错

 但是不管怎么说,动作文件被压缩好了。

扫描二维码关注公众号,回复: 4080112 查看本文章

猜你喜欢

转载自blog.csdn.net/yijiankun100/article/details/83148521