using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; public class LTCompressor { private const string COMPRESSED_PATH = "Assets/Art/Animations/compressed"; private const string NEED_COMPRESS_PATH = "Assets/Art/Animations/animator"; private static List _compressedFiles; [MenuItem("Tools/资源压缩/压缩所有动画")] public static void CompressAll() { // 确保路径存在 _InitCompressPath(); // 加载所有需要的动画 var realPath = Application.dataPath.Replace("Assets", NEED_COMPRESS_PATH); var allFiles = System.IO.Directory.GetFiles(realPath, "*.overrideController", System.IO.SearchOption.TopDirectoryOnly); var filterFiles = new List(); foreach (var fileName in allFiles) { var onlyFileName = System.IO.Path.GetFileName(fileName); var assetPath = NEED_COMPRESS_PATH + "/" + onlyFileName; filterFiles.Add(assetPath); } // 挨个处理 _compressedFiles = new List(); foreach (var assetPath in filterFiles) { var loadController = AssetDatabase.LoadAssetAtPath(assetPath); if (loadController == null) { Debug.LogError("读取文件发生错误:" + assetPath); return; } // 检出 // VersionControlSystem.Checkout(assetPath); _CompressAnim(loadController); } AssetDatabase.Refresh(); } private static void _InitCompressPath() { var realPath = Application.dataPath.Replace("Assets", COMPRESSED_PATH); if (!System.IO.Directory.Exists(realPath)) { System.IO.Directory.CreateDirectory(realPath); } } private static void _CompressAnim(AnimatorOverrideController overrideController) { // 读取所有的动画 var overrideClips = new List>(); overrideController.GetOverrides(overrideClips); var newClips = new List>(); // 挨个处理 for (var i = 0; i < overrideClips.Count; ++i) { var clipPair = overrideClips[i]; var srcClip = clipPair.Key; var dstClip = clipPair.Value; if (srcClip == null && dstClip == null) { // 双为空才报错 Debug.LogError("动画为空,请检查:" + overrideController.name); continue; } AnimationClip compressedClip; if (dstClip == null) { compressedClip = _CompressClip(srcClip); } else { compressedClip = _CompressClip(dstClip); } if (compressedClip == null) { Debug.LogError("压缩动画失败:" + srcClip.name); } var newClip = new KeyValuePair(srcClip, compressedClip); newClips.Add(newClip); } // 重新设置 overrideController.ApplyOverrides(newClips); } private static bool _CheckIsAllwaysOne(EditorCurveBinding curveBinding, AnimationClip clip) { // 检查是否一直为1 var curve = AnimationUtility.GetEditorCurve(clip, curveBinding); var keys = curve.keys; var isAllwaysOne = true; for (var i = 0; i < keys.Length; ++i) { var key = keys[i]; if (Math.Abs(key.value - 1) > 0.01f) { isAllwaysOne = false; break; } } return isAllwaysOne; } private static AnimationClip _CompressClip(AnimationClip clip) { var clipName = clip.name; var savePath = COMPRESSED_PATH + "/compressed_" + clipName + ".anim"; if (_compressedFiles.Contains(savePath)) { var loadClip = AssetDatabase.LoadAssetAtPath(savePath); return loadClip; } _compressedFiles.Add(savePath); // 如果名字中包含compressed,则不再压缩 if (clip.name.StartsWith("compressed")) { return clip; } // 读取所有的曲线,删除scale曲线 var curveBindings = AnimationUtility.GetCurveBindings(clip); var newCurveBindings = new List(); foreach (var curveBinding in curveBindings) { // Debug.Log("curveBinding.propertyName:" + curveBinding.propertyName); if (curveBinding.propertyName.Contains("m_LocalScale") && _CheckIsAllwaysOne(curveBinding, clip)) { continue; } newCurveBindings.Add(curveBinding); } // 截取float精度为4位 foreach (var curveBinding in newCurveBindings) { var curve = AnimationUtility.GetEditorCurve(clip, curveBinding); var keys = curve.keys; for (var i = 0; i < keys.Length; ++i) { var key = keys[i]; key.value = Mathf.Round(key.value * 10000) / 10000; key.outWeight = Mathf.Round(key.outWeight * 10000) / 10000; key.inWeight = Mathf.Round(key.inWeight * 10000) / 10000; keys[i] = key; } curve.keys = keys; AnimationUtility.SetEditorCurve(clip, curveBinding, curve); } // 创建新的clip,储存为compressed_原有名称 var newClip = new AnimationClip(); foreach (var curveBinding in newCurveBindings) { var curve = AnimationUtility.GetEditorCurve(clip, curveBinding); AnimationUtility.SetEditorCurve(newClip, curveBinding, curve); } AssetDatabase.CreateAsset(newClip, savePath); return newClip; } }