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; } private static string _GetPathFinalName(string bipPath) { var splitNames = bipPath.Split('/'); var finalName = splitNames[^1]; return finalName; } public static AnimationClip AutoCompress(AnimationClip needCompressClip) { // 如果名字中包含compressed,则不再压缩 if (needCompressClip.name.StartsWith("compressed")) { return needCompressClip; } var savePath = Application.dataPath.Replace("Assets", COMPRESSED_PATH); if (!System.IO.Directory.Exists(savePath)) { System.IO.Directory.CreateDirectory(savePath); } var compressPath = COMPRESSED_PATH + "/compressed_" + needCompressClip.name + ".anim"; var loadClip = AssetDatabase.LoadAssetAtPath(compressPath); if (loadClip != null) { return loadClip; } var curveBindings = AnimationUtility.GetCurveBindings(needCompressClip); var newCurveBindings = new List(); foreach (var curveBinding in curveBindings) { // Debug.Log("curveBinding.propertyName:" + curveBinding.propertyName); // 读取所有的曲线,删除scale曲线 if (curveBinding.propertyName.Contains("m_LocalScale")) { continue; } // 删除名字包含Bip001 的position曲线 // var finalName = _GetPathFinalName(curveBinding.path); // if (curveBinding.propertyName.Contains("m_LocalPosition") // && finalName.Contains("Bip001 ")) // { // continue; // } newCurveBindings.Add(curveBinding); } // 截取float精度为4位 foreach (var curveBinding in newCurveBindings) { var curve = AnimationUtility.GetEditorCurve(needCompressClip, 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(needCompressClip, curveBinding, curve); } // 创建新的clip,储存为compressed_原有名称 var newClip = new AnimationClip(); foreach (var curveBinding in newCurveBindings) { var curve = AnimationUtility.GetEditorCurve(needCompressClip, curveBinding); AnimationUtility.SetEditorCurve(newClip, curveBinding, curve); } // 设置帧率 newClip.frameRate = 30; // Set loop time var settings = AnimationUtility.GetAnimationClipSettings(newClip); var oldAnimSettings = AnimationUtility.GetAnimationClipSettings(needCompressClip); settings.loopTime = oldAnimSettings.loopTime; settings.loopBlend = oldAnimSettings.loopBlend; settings.cycleOffset = oldAnimSettings.cycleOffset; settings.loopBlendOrientation = oldAnimSettings.loopBlendOrientation; settings.loopBlendPositionY = oldAnimSettings.loopBlendPositionY; settings.loopBlendPositionXZ = oldAnimSettings.loopBlendPositionXZ; AnimationUtility.SetAnimationClipSettings(newClip, settings); AssetDatabase.CreateAsset(newClip, compressPath); return newClip; } }