using System;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using System.Reflection;
|
using UnityEditor;
|
using System.IO;
|
|
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 UnityEngine.Profiling.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)
|
{
|
//DesignDebug.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(false, 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(Selection.GetFiltered(typeof(object), SelectionMode.Assets));
|
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();
|
DebugEx.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(UnityEngine.Object[] _objs)
|
{
|
string[] guids = null;
|
List<string> path = new List<string>();
|
List<AnimationOpt> assets = new List<AnimationOpt>();
|
UnityEngine.Object[] objs = _objs;
|
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]));
|
}
|
if (path.Count > 0)
|
guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(AnimationClip).ToString().Replace("UnityEngine.", "")), path.ToArray());
|
else
|
guids = new string[] { };
|
}
|
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;
|
}
|
}
|
}
|