|
|
- using System.Collections;
- using System.Collections.Generic;
- using UnityEditor;
- using System.IO;
- using UnityEngine;
- using UnityEditor.Animations;
- using System.Linq;
- using System.Text;
-
- public class AnimationHelper
- {
- static string[] animations_path =
- {
- "",
- // @"Assets/LuaFramework/AssetBundleRes/scene/object/role",
- //@"Assets/LuaFramework/AssetBundleRes/scene/object/npc",
- //@"Assets/LuaFramework/AssetBundleRes/scene/object/monster",
- //@"Assets/LuaFramework/AssetBundleRes/scene/object/mount",
- //@"Assets/LuaFramework/AssetBundleRes/scene/object/wing",
- //@"Assets/LuaFramework/AssetBundleRes/scene/object/headwear",
- };
-
- //特殊路径过滤
- static string[] mask_path =
- {
- };
-
- static private string ErrorString = "";
- static private string LogString = "";
- static private string SpeicalLogString = "";
- static Dictionary<string, List<ClipAnimData>> allDatas = new Dictionary<string, List<ClipAnimData>>(); //所有正常的数据
- static Dictionary<string, List<ClipAnimData>> allSpecialDatas = new Dictionary<string, List<ClipAnimData>>(); //所有异常数据目录,比如同一个目录下有多个action
- static Dictionary<string, string> allTempPaths = new Dictionary<string, string>(); //所有动画文件,路径缓存
- static bool needScleProcess = true;
-
- public class ClipAnimData
- {
- public string _name; //fbx中动画的名字
- public AnimationClip _clip; //生成的新的动画文件
- public string _path; //原fbx文件路径
- public string _clip_file_path; //chip文件路径
- public ClipAnimData(string name, string path, AnimationClip clip, string clip_file_path)
- {
- _name = name;
- _clip = clip;
- _path = path;
- _clip_file_path = clip_file_path;
- }
- };
-
-
- public class ReplaceClipAnimData
- {
- public string _stateName; //状态机的名字
- public Motion _motion; //状态机的动画
- public ClipAnimData _clip; //状态机的新动画数据
- public ReplaceClipAnimData(string name, Motion motion, ClipAnimData clip)
- {
- _stateName = name;
- _motion = motion;
- _clip = clip;
- }
- };
-
- //将目标路径下的fbx转为anim,并挂到action controller
- // [MenuItem("AnimationHelper/Format Animations By Config")]
- [MenuItem("AnimationHelper/步骤1. 格式化选中路径动作(剔除曲线)")]
- public static void FormatSelectPath()
- {
- needScleProcess = true;
- FormatAllAnimations();
- }
-
- [MenuItem("AnimationHelper/步骤1. 格式化选中路径动作(保留曲线)")]
- public static void FormatSelectPathWithoutScale()
- {
- needScleProcess = false;
- FormatAllAnimations();
- }
-
- public static void FormatAllAnimations()
- {
- if (!EditorUtility.DisplayDialog("提示", "首次格式化动作文件,需要持续十几分钟,是否继续?", "继续", "取消"))
- return;
-
- Object[] objs = Selection.objects;
- if(objs.Length > 0)
- {
- if(objs.Length > 1)
- {
- LogString = "只能操作一个文件夹";
- EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- return;
- }
-
- animations_path[0] = AssetDatabase.GetAssetPath(objs[0]);
- // LogString = animations_path[0];
- // EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- // return;
- }
- else{
- LogString = "未选中需要压缩的文件夹,如:role等";
- Debug.Log(LogString);
- EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- return;
- }
-
- //查找指定路径下指定类型的所有资源,返回的是资源GUID
- string[] guids = AssetDatabase.FindAssets("action", animations_path);
-
-
- //从GUID获得资源所在路径
- List<string> paths = new List<string>();
- guids.ToList().ForEach(m => paths.Add(AssetDatabase.GUIDToAssetPath(m)));
- ErrorString = "异常处理的文件日志\n";
- LogString = "需要处理的文件日志\n";
- SpeicalLogString = "特殊文件日志\n";
-
- allDatas.Clear();
- allSpecialDatas.Clear();
- allTempPaths.Clear();
- for (int i = 0; i < paths.Count; i++)
- {
- AnimatorController controller = AssetDatabase.LoadAssetAtPath(paths[i], typeof(AnimatorController)) as AnimatorController;
- if (controller != null)
- {
- List<ClipAnimData> clipDatas = new List<ClipAnimData>();
- var path = paths[i];
- var goName = controller.name + ".controller";
- path = path.Replace(@"/" + goName, "");
-
- //过滤的路径不处理
- if (IsMakPath(path))
- continue;
-
- string[] fbxGuids = AssetDatabase.FindAssets("t:GameObject", new string[] { path });
- if(fbxGuids.Length > 0)
- {
- foreach (var guid in fbxGuids)
- {
- string file = AssetDatabase.GUIDToAssetPath(guid);
- CheckFBXAnimCompression(file);
- ClipAnimData clip = CreateNewAnimationClip(file);
- if (clip != null)
- {
- clipDatas.Add(clip);
- }
-
- if (File.Exists(file))
- DeleteFile(file);
- }
- }
- if (clipDatas.Count > 0)
- {
- AppendLog("============> action path = " + path + " ================= > actionName = " + goName);
- if (allTempPaths.ContainsKey(path))
- {
- AppendLog(" 同目录下存在2个动画控制器 [" + path + "]");
- allSpecialDatas.Add(paths[i], clipDatas);
- var value = allTempPaths[path];
- if (allDatas.ContainsKey(value))
- {
- allSpecialDatas.Add(value, allDatas[value]);
- allDatas.Remove(value);
- }
- }
- else
- {
- allTempPaths.Add(path, paths[i]);
- allDatas.Add(paths[i], clipDatas);
- }
- }
- }
- }
- if (allDatas.Count > 0)
- {
- foreach (var item in allDatas)
- {
- RePlaceMotion(item.Key, item.Value);
- }
-
- //去掉所有anim文件不需要的数据
- DeleteAllAnimUnuseData(allDatas);
-
- }
-
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- Debug.Log(LogString);
- Debug.Log(ErrorString);
- Debug.Log(SpeicalLogString);
- string show_tips = "FormatAllAnimations完成, 共生成替换了"+guids.Length+"个action";
- EditorUtility.DisplayDialog("提示", show_tips, "确定");
- }
-
- //将选中的fbx转为anim
- // [MenuItem("AnimationHelper/格式化选中路径动作")]
- // public static void FormatTargetAnimation()
- // {
-
- // LogString = "动作格式化日志:\n";
- // Object[] objs = Selection.objects;
- // if(objs.Length > 0)
- // {
- // foreach (var item in objs)
- // {
- // string path = AssetDatabase.GetAssetPath(item);
- // AppendLog("path = " + path );
- // // var clip = CreateNewAnimationClip(path);
- // // if(clip != null)
- // // AppendLog("path = " + path + ", actionName = " + clip._name);
- // }
- // }
- // else{
- // LogString = "未选中需要压缩的文件夹,如:role等";
- // }
- // AssetDatabase.SaveAssets();
- // AssetDatabase.Refresh();
- // Debug.Log(LogString);
- // EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- // }
-
- //对目标路径下的所有anim执行一遍精度优化
- // [MenuItem("AnimationHelper/Process all Animations")]
- public static void ProcessAnimation()
- {
- //查找指定路径下指定类型的所有资源,返回的是资源GUID
- string[] guids = AssetDatabase.FindAssets("t:animationClip", animations_path);
- //从GUID获得资源所在路径
- List<string> paths = new List<string>();
- guids.ToList().ForEach(m => paths.Add(AssetDatabase.GUIDToAssetPath(m)));
-
- foreach (var p in paths)
- {
- AnimationClip tempClip = AssetDatabase.LoadAssetAtPath(p, typeof(AnimationClip)) as AnimationClip;
- if (tempClip != null)
- {
- OnProcessAnimationClip(tempClip, p);
- }
- }
-
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
-
- string show_tips = "Process Animation 完成";
- EditorUtility.DisplayDialog("提示", show_tips, "确定");
- }
-
- //重新关联AnimatorController中的动画
- static bool RePlaceMotion(string path, List<ClipAnimData> list)
- {
- bool result = true;
- AnimatorController animatorController = AssetDatabase.LoadAssetAtPath(path, typeof(AnimatorController)) as AnimatorController;
- if (animatorController != null && list != null && list.Count > 0)
- {
- List<ReplaceClipAnimData> replaceData = new List<ReplaceClipAnimData>();
- //取得AnimatorController中的动画状态机
- AnimatorStateMachine stateMachine = animatorController.layers[0].stateMachine;
- for (int i = 0; i < stateMachine.states.Length; i++)
- {
- if (stateMachine.states[i].state == null)
- {
- AppendErrorLog(" not find statue, path = [ " + path + "]");
- result = false;
- continue;
- }
- if (stateMachine.states[i].state.motion == null)
- {
-
- AppendLog(" not find statue motion, state = [" + stateMachine.states[i].state.name + " ]" + " + path = [ " + path + "]");
- //result = false;
- //continue;
- }
-
- string motionName = stateMachine.states[i].state.name;
-
- ClipAnimData t = null;
- //原动画状态机的名字和生成的动画片段名字相匹配,才会替换
- for (int j = 0; j < list.Count; j++)
- {
- if (list[j]._name == motionName)
- {
- t = list[j];
- break;
- }
- }
- if (t != null)
- {
- replaceData.Add(new ReplaceClipAnimData(stateMachine.states[i].state.name, stateMachine.states[i].state.motion, t));
- }
- else
- {
- AppendErrorLog(" not find AnimationClip motionName = [" + motionName + "]");
- }
- }
- if (replaceData.Count > 0)
- {
- foreach (var item in replaceData)
- {
- var stateName = item._stateName;
- var motion = item._motion;
- var clip = item._clip;
- for (int i = 0; i < stateMachine.states.Length; i++)
- {
- if (stateName == stateMachine.states[i].state.name)
- {
- stateMachine.states[i].state.motion = clip._clip;
- //替换之后,删除原来的FBX文件
- DeleteFile(clip._path);
- break;
- }
- }
- }
- }
- }
- return result;
- }
-
- //根据原来的FBx文件生成新的动画片段
- static ClipAnimData CreateNewAnimationClip(string path)
- {
- Object obj = AssetDatabase.LoadAssetAtPath(path, typeof(Object)) as Object;
- AnimationClip oldClip = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
- if (obj != null && oldClip != null)
- {
- AnimationClip newClip = new AnimationClip();
- EditorUtility.CopySerialized(oldClip, newClip);
- string newPath = path;
- newPath = newPath.Replace(obj.name + ".FBX", "");
- string newName = obj.name;
- newName = newName.Replace(@"@", @"_new@");
- OnProcessAnimationClip(newClip, path);
- //若生成的文件以及存在,删除掉
- if (File.Exists(newPath + newName + ".anim"))
- {
- DeleteFile(newPath + newName + ".anim");
- }
- //生成新的动画片段
- AssetDatabase.CreateAsset(newClip, newPath + newName + ".anim");
- return new ClipAnimData(oldClip.name, path, newClip, newPath + newName + ".anim");
- }
- return null;
- }
-
- //动画片段精度压缩
- static void OnProcessAnimationClip(AnimationClip clip, string path)
- {
- // bool needScleProcess = true;
- // if (path.Contains("object/role") && path.Contains("show"))
- // {
- // needScleProcess = false;
- // }
- // else if (path.Contains("object/pet"))
- // {
- // needScleProcess = false;
- // }
-
- // Debug.Log("path" + path + "; needScleProcess"+needScleProcess);
-
- if (needScleProcess)
- {
- foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(clip))
- {
- string name = theCurveBinding.propertyName.ToLower();
- if (name.Contains("scale"))
- {
- AnimationUtility.SetEditorCurve(clip, theCurveBinding, null);
- }
- }
- }
-
- //浮点数精度压缩到f3
- AnimationClipCurveData[] curves = null;
- curves = AnimationUtility.GetAllCurves(clip);
- Keyframe key;
- Keyframe[] keyFrames;
- string formatType = "f3";
- if (needScleProcess == false)
- {
- formatType = "f5";
- }
- for (int ii = 0; ii < curves.Length; ++ii)
- {
- AnimationClipCurveData curveDate = curves[ii];
- if (curveDate.curve == null || curveDate.curve.keys == null)
- {
- continue;
- }
- keyFrames = curveDate.curve.keys;
- for (int i = 0; i < keyFrames.Length; i++)
- {
- key = keyFrames[i];
- key.value = float.Parse(key.value.ToString(formatType));
- key.inTangent = float.Parse(key.inTangent.ToString(formatType));
- key.outTangent = float.Parse(key.outTangent.ToString(formatType));
- keyFrames[i] = key;
- }
- curveDate.curve.keys = keyFrames;
- clip.SetCurve(curveDate.path, curveDate.type, curveDate.propertyName, curveDate.curve);
- }
-
- /*
- Keyframe[] keyFrames;
- Keyframe key;
- foreach (var binding in AnimationUtility.GetCurveBindings(clip))
- {
- AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding);
- keyFrames = curve.keys;
- for (int i = 0; i < keyFrames.Length; i++)
- {
- key = keyFrames[i];
- key.value = float.Parse(key.value.ToString("f3"));
- key.inTangent = float.Parse(key.inTangent.ToString("f3"));
- key.outTangent = float.Parse(key.outTangent.ToString("f3"));
- keyFrames[i] = key;
- }
- curve.keys = keyFrames;
- clip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
- }
- */
- }
-
- //删除文件
- public static void DeleteFile(string path)
- {
- AssetDatabase.DeleteAsset(path);
- }
-
- //拼接错误log
- public static void AppendErrorLog(string log)
- {
- ErrorString = ErrorString + log + "\n";
- }
-
- //拼接log
- public static void AppendLog(string log, int logLevel = 0)
- {
- if (logLevel == 0)
- LogString = LogString + log + "\n";
- else
- SpeicalLogString = SpeicalLogString + log + "\n";
- }
-
- public static bool IsMakPath(string path)
- {
- if(mask_path.Length > 0)
- {
- foreach (var p in mask_path)
- {
- if (p == path)
- return true;
- }
- }
- return false;
- }
-
-
- //去除所选文件下中anim的不需要的参数
- [MenuItem("AnimationHelper/步骤2. 去除anim的冗余参数")]
- public static void FormatAllAnimationChilp()
- {
- if (!EditorUtility.DisplayDialog("提示", "首次格式化动作文件,需要持续十几分钟,是否继续?", "继续", "取消"))
- return;
- Object[] objs = Selection.objects;
- if (objs.Length > 0)
- {
- if (objs.Length > 1)
- {
- LogString = "只能操作一个文件夹";
- EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- return;
- }
- animations_path[0] = AssetDatabase.GetAssetPath(objs[0]);
- }
- else
- {
- LogString = "未选中需要压缩的文件夹,如:role等";
- Debug.Log(LogString);
- EditorUtility.DisplayDialog("Format Target Animation", LogString, "确定");
- return;
- }
-
- //查找指定路径下指定类型的所有资源,返回的是资源GUID
- string[] guids = AssetDatabase.FindAssets("action", animations_path);
-
-
- //从GUID获得资源所在路径
- List<string> paths = new List<string>();
- guids.ToList().ForEach(m => paths.Add(AssetDatabase.GUIDToAssetPath(m)));
- ErrorString = "异常处理的文件日志\n";
- LogString = "需要处理的文件日志\n";
- SpeicalLogString = "特殊文件日志\n";
-
- allDatas.Clear();
- allSpecialDatas.Clear();
- allTempPaths.Clear();
-
- string[] chipGuids = AssetDatabase.FindAssets("t:AnimationClip", new string[] { animations_path[0]});
- if (chipGuids.Length > 0)
- {
- foreach (var guid in chipGuids)
- {
- string path = AssetDatabase.GUIDToAssetPath(guid);
- ProressDeleteAnimUnuseData(path);
- }
- }
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- Debug.Log(LogString);
- Debug.Log(ErrorString);
- Debug.Log(SpeicalLogString);
- string show_tips = "FormatAllAnimationChilp完成, 共生成替换了" + guids.Length + "个action";
- EditorUtility.DisplayDialog("提示", show_tips, "确定");
- }
-
- //去掉anim文件中的 intWeight 和 outWeight
- public static void DeleteAllAnimUnuseData(Dictionary<string, List<ClipAnimData>> data)
- {
- if (data == null || data.Count == 0) return;
- foreach (var item in data)
- {
- List<ClipAnimData> list = item.Value;
- if(list.Count > 0)
- {
- for(int i = 0; i< list.Count; i++)
- {
- ProressDeleteAnimUnuseData(list[i]._clip_file_path);
- }
-
- }
- RePlaceMotion(item.Key, item.Value);
- }
- }
-
- //去掉anim文件中的 intWeight 和 outWeight
- public static void ProressDeleteAnimUnuseData(string path)
- {
- string[] result = File.ReadAllLines(path, Encoding.UTF8);
-
- if (result.Length > 0)
- {
- List<string> new_list = new List<string>();
- for (int k = 0; k < result.Length; k++)
- {
- string content = result[k];
- if (!content.Contains("inWeight:") && !content.Contains("outWeight:") && !content.Contains("weightedMode:") )
- {
- new_list.Add( content);
- }
- }
- File.WriteAllLines(path, new_list);
- }
- }
-
- //修改压缩格式
- public static void CheckFBXAnimCompression(string path)
- {
- ModelImporter mi = AssetImporter.GetAtPath(path) as ModelImporter;
- mi.animationCompression = ModelImporterAnimationCompression.Optimal;
- AssetDatabase.SaveAssets();
- }
- }
|