关于动画文件的压缩,其实前辈们已经讲得非常详尽了:
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%!虽然不是真机测试结果,但足以说明动画文件优化的提升空间有多大。
小伙伴儿门赶紧在自己的项目中测试一下吧!