AnimationClipper.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using UnityEditor;
  2. using UnityEngine;
  3. using System.IO;
  4. using System.Collections.Generic;
  5. public class AnimationClipper : EditorWindow
  6. {
  7. private static AnimationClipper _window = null;
  8. [MenuItem("Tools/优化/动作/动画剪裁")]
  9. public static void ClipAnimation()
  10. {
  11. _window = EditorWindow.GetWindow<AnimationClipper>(false, "AnimationClipWindow", true);
  12. _window.Show();
  13. }
  14. public void OnGUI()
  15. {
  16. if (GUILayout.Button("开始剪裁"))
  17. {
  18. foreach(var obj in Selection.objects)
  19. {
  20. if(obj.GetType() == typeof(AnimationClip))
  21. {
  22. ClipAnimationCurveData((AnimationClip)obj);
  23. EditorUtility.SetDirty(obj);
  24. }
  25. else
  26. {
  27. var path = AssetDatabase.GetAssetPath(obj);
  28. if(Directory.Exists(path))
  29. {
  30. ClipAnimationsInDirectory(path);
  31. }
  32. }
  33. }
  34. AssetDatabase.SaveAssets();
  35. }
  36. }
  37. private static void ClipAnimationsInDirectory(string path)
  38. {
  39. string pathDir = FileUtils.ExtractAssetRelativePath(path);
  40. var files = Directory.GetFiles(pathDir, "*.anim", SearchOption.AllDirectories);
  41. foreach (var file in files)
  42. {
  43. string fileName = FileUtils.ExtractAssetRelativePath(file);
  44. var clip = (AnimationClip)AssetDatabase.LoadAssetAtPath(fileName, typeof(AnimationClip));
  45. if (null != clip)
  46. {
  47. ClipAnimationCurveData((AnimationClip)clip);
  48. EditorUtility.SetDirty(clip);
  49. }
  50. }
  51. }
  52. public static bool ClipAnimationCurveData(AnimationClip clip)
  53. {
  54. if (clip == null)
  55. {
  56. return false;
  57. }
  58. EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(clip);
  59. if (curveBindings == null)
  60. {
  61. return false;
  62. }
  63. AnimationCurve[] curves = new AnimationCurve[curveBindings.Length];
  64. for (int idx =0; idx < curveBindings.Length;idx++)
  65. {
  66. AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, curveBindings[idx]);
  67. curves[idx] = curve;
  68. }
  69. // 清除原来所有的数据
  70. clip.ClearCurves();
  71. float len = clip.length;
  72. for (int idx = 0; idx < curveBindings.Length; idx++)
  73. {
  74. EditorCurveBinding ecb = curveBindings[idx];
  75. AnimationCurve curve = curves[idx];
  76. // 进行过滤
  77. if (IsFilterCurveData(curveBindings[idx].propertyName, curve))
  78. {
  79. continue;
  80. }
  81. // 将数据存回去
  82. clip.SetCurve(ecb.path, ecb.type, ecb.propertyName, curve);
  83. }
  84. curves = null;
  85. return true;
  86. }
  87. public static bool IsFilterCurveData(string propertyName, AnimationCurve curve)
  88. {
  89. if (propertyName.Contains("Position"))
  90. {
  91. return IsNoEffectCurvy(curve, 0);
  92. }
  93. if (propertyName.Contains("Scale"))
  94. {
  95. return IsNoEffectCurvy(curve, 1, true);
  96. }
  97. if (propertyName.Contains("Rotation"))
  98. {
  99. return IsNoEffectCurvy(curve, 0, true);
  100. }
  101. return false;
  102. }
  103. public static bool IsNoEffectCurvy(AnimationCurve curve, float identity, bool reserveIdentity = false)
  104. {
  105. if(curve.keys == null || curve.keys.Length == 0)
  106. {
  107. return true;
  108. }
  109. var keys = new List<Keyframe>(curve.keys);
  110. // 减去多余的帧
  111. for(int i = 0; i < keys.Count;)
  112. {
  113. if(i - 1 < 0)
  114. {
  115. i++;
  116. continue;
  117. }
  118. if(i + 1 >= keys.Count)
  119. {
  120. i++;
  121. continue;
  122. }
  123. // 如果一帧的前一帧和后一帧都和当前帧相等,那么可以删除自己
  124. if (IsKeyFrameEqual(keys[i-1], keys[i]) && IsKeyFrameEqual(keys[i], keys[i+1]))
  125. {
  126. keys.RemoveAt(i);
  127. continue;
  128. }
  129. i++;
  130. }
  131. // 如果只剩下2帧了,那么这两帧肯定是相等的,根据参数判断是否整个曲线都去掉
  132. if(keys.Count <= 2)
  133. {
  134. if (Mathf.Abs(keys[0].value - identity) < 0.001f && !reserveIdentity)
  135. {
  136. return true;
  137. }
  138. }
  139. curve.keys = keys.ToArray();
  140. return false;
  141. }
  142. private static bool IsKeyFrameEqual(Keyframe frame1, Keyframe frame2)
  143. {
  144. if (Mathf.Abs(frame1.value - frame2.value) > 0.001f)
  145. {
  146. return false;
  147. }
  148. if (Mathf.Abs(frame1.inTangent - frame2.inTangent) > 0.001f)
  149. {
  150. return false;
  151. }
  152. if (Mathf.Abs(frame1.outTangent - frame2.outTangent) > 0.001f)
  153. {
  154. return false;
  155. }
  156. if (Mathf.Abs(frame1.tangentMode - frame2.tangentMode) > 0.001f)
  157. {
  158. return false;
  159. }
  160. return true;
  161. }
  162. }