using UnityEngine; using UnityEditor; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using System.Text; using System.IO; using System.Drawing; using System.Text.RegularExpressions; using System; public class ModelChecker : EditorWindow { private static ModelChecker instance; List _infoList = new List(); static Texture2D _targetPic; static string _pathRoot; static float _alpha_cut_off = 0f; static int _horizontalSpace = 0; static int _verticalSpace = 0; static int _rate = 200; static int _rateImage = 1; static int _foreceHight = 23; static string splitChar = "\t"; static string _ignore = "Tools,Fonts,terrain,effect,action,weapon"; static string[] formatOption = new string[] { "CSV", "xls", "txt" }; static int indexOfFormat; static string[] sortKey = new string[] { "骨骼数", "面数" ,"顶点数"}; static int indexOfSortKey; static string[] sortType = new string[] { "升序", "降序" }; static int indexOfSortType = 0; static SaveType _saveType = SaveType.csv; static bool _ignore_effect = false; static Encoding ENCODING = Encoding.GetEncoding("GB2312"); static string titleStr; static bool _isCheckEmpty = true; static string[] _ignore_list; static string des_end_str; //输出文件的后缀名 static List error_list = new List(); static List warning_list = new List(); static string _guiChecker; static int _checkCount=10000; bool _tog; bool _tog2; bool _tog3; [MenuItem("Tools/检查模型")] static void ShowExcelTools() { Init(); instance.Show(); } enum SaveType { csv = 0, xls, txt, } void OnGUI() { DrawOptions(); } static bool Get2Flag(int num) { if (num < 1) return false; return (num & num - 1) == 0; } private void DrawOptions() { _pathRoot = EditorGUILayout.TextField("指定目录", _pathRoot); _ignore = EditorGUILayout.TextField("忽略目录关键字", _ignore); EditorGUILayout.HelpBox("检查的时候会忽略有上面关键字的目录,用逗号‘,’分割", MessageType.Info); _ignore_list = _ignore.Split(','); if (GUILayout.Button("scene目录")) { _pathRoot = "Assets/LuaFramework/AssetBundleRes/scene"; } if (GUILayout.Button("资源目录")) { _pathRoot = "Assets/LuaFramework/AssetBundleRes"; } EditorGUILayout.Space(); EditorGUILayout.Space(); indexOfFormat = EditorGUILayout.Popup("储存格式", indexOfFormat, formatOption); _saveType = (SaveType)indexOfFormat; if (_saveType == SaveType.csv) { splitChar = ","; des_end_str = ".csv"; } else if (_saveType == SaveType.xls) { splitChar = "\t"; des_end_str = ".xls"; } else if (_saveType == SaveType.txt) { splitChar = "\r\n"; des_end_str = ".txt"; } indexOfSortKey = EditorGUILayout.Popup("排序关键字", indexOfSortKey, sortKey); indexOfSortType = EditorGUILayout.Popup("排序类型", indexOfSortType, sortType); EditorGUILayout.Space(); EditorGUILayout.Space(); titleStr = "骨骼数" + splitChar + "定点数" + splitChar + "三角面数" + splitChar + "文件路径";// + splitChar + "是否有空余像素" + splitChar + "非空范围X" + splitChar + "非空范围Y" + splitChar + "特效文件NPOT" + splitChar + "路径"; _rate = EditorGUILayout.IntField("查找文件速度(文件数/帧)", _rate); EditorGUILayout.IntField("检查文件速度(文件数/帧)", 1); EditorGUILayout.HelpBox("因为算法原因,只能一个个检查,无法更改", MessageType.Info); if (GUILayout.Button("转换")) { EditorCoroutineRunner.StartEditorCoroutine(Conver()); } EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.HelpBox("-----------------------------------以下测试用-------------------------------------",MessageType.Info); _guiChecker = EditorGUILayout.TextField("GUID", _guiChecker); if(GUILayout.Button("GUID转换地址")) { Debug.LogError(AssetDatabase.GUIDToAssetPath(_guiChecker)); } _checkCount = EditorGUILayout.IntField("最多检查文件数", _checkCount); } class ModelInfo { public string filePath; public int vertsCount; public int trisCount; public int bonesCount; public ModelInfo(string clearPath) { filePath = clearPath; } public string GetInfo() { string str = ""; str += bonesCount + splitChar; str += vertsCount + splitChar; str += trisCount + splitChar; str += filePath + splitChar; //str += "\n"; return str; } } int CompareDinosBySize(ModelInfo t1, ModelInfo t2) { if(indexOfSortKey == 0) { if(indexOfSortType == 0) { return t1.bonesCount - t2.bonesCount; } else { return t2.bonesCount - t1.bonesCount; } } else if(indexOfSortKey == 1) { if(indexOfSortType == 0) { return t1.trisCount - t2.trisCount; } else { return t2.trisCount - t1.trisCount; } } else if(indexOfSortKey == 2) { if (indexOfSortType == 0) { return t1.vertsCount - t2.vertsCount; } else { return t2.vertsCount - t1.vertsCount; } } return 0; } bool IsIgonrePath(string path) { foreach (var flag in _ignore_list) { if (path.ToLower().Contains(flag.ToLower())) { return true; } } return false; } IEnumerator Conver() { string dateStr = DateTime.Now.Hour.ToString() + "_" + DateTime.Now.Minute.ToString() + "_" + DateTime.Now.Second.ToString(); string newDir = Application.dataPath.Replace("Assets", "") + "/model_output_" + dateStr + des_end_str; try { if(File.Exists(newDir)) { var test = File.Open(newDir, FileMode.Open); test.Close(); test.Dispose(); } } catch (IOException exp) { EditorUtility.DisplayDialog("提示", "错误,请先关闭写入目录的文件 ", "好的呢", ""); Debug.LogError(exp); yield break; } var files = Directory.GetFiles(_pathRoot.Replace("Assets", Application.dataPath), "*.fbx*", SearchOption.AllDirectories); //var files2 = Directory.GetFiles(_pathRoot.Replace("Assets", Application.dataPath), "*.FBX*", SearchOption.AllDirectories); List modelPath = new List(); float count = 0; foreach (var file in files) { count++; if (count % _rate == 0) { yield return 1; } if (IsIgonrePath(file)) { continue; } if (file.ToLower().EndsWith(".fbx") && !file.ToLower().Contains("@")) { var clearPaht = file.Replace(Application.dataPath,"Assets"); modelPath.Add(clearPaht); if (modelPath.Count > _checkCount) { break; } EditorUtility.DisplayProgressBar("查找文件中的FBX···"+ modelPath.Count, file, count / files.Length); } } if(!EditorUtility.DisplayDialog("提示", "一共查找到"+ modelPath.Count+ "个文件,是否继续\n因为只能一个个检查,所以数量大会很慢哦\n\n520个文件大概5到10分钟", "继续", "取消")) { EditorUtility.ClearProgressBar(); yield break; } error_list.Clear(); warning_list.Clear(); _infoList.Clear(); count = 0; foreach (var singPath in modelPath) { count++; //if(count > 180 && count < 200) //{ //} //else //{ // continue; //} try { CheckSinglModel(singPath); } catch (Exception exp) { error_list.Add(singPath); Debug.LogError(singPath + "\n\n" + exp); } if (count % _rateImage == 0) { yield return 1; } EditorUtility.DisplayProgressBar("检查模型中···(共" + modelPath.Count + "个)" + count + "/" + modelPath.Count, singPath, count / modelPath.Count); } _infoList.Sort(CompareDinosBySize); count = 0; List str = new List(); str.Add(titleStr); foreach (var info in _infoList) { count++; str.Add(info.GetInfo()); //if (count % _rateImage * 30 == 0) //{ // yield return 1; //} EditorUtility.DisplayProgressBar("整理文件中···", "不想告诉你当前进度·····", count / _infoList.Count); } str.Add("以下文件出错"); str.AddRange(error_list); str.Add("以下文件读取时候出现异常,可能出错"); str.AddRange(warning_list); EditorUtility.DisplayProgressBar("写入文件中···", "", 0); if (_infoList.Count > 0) { try { File.WriteAllLines(newDir, str.ToArray(), ENCODING); } catch (IOException exp) { EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("提示", "错误,请先关闭写入目录的文件 ", "好的呢", ""); yield break; } } EditorUtility.DisplayDialog("提示", "扫描完成", "GOOD", ""); EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(); } void CheckSinglModel(string path) { path = path.Replace(@"\","/"); if(path.Contains("@")) { return; } ModelInfo info = new ModelInfo(path); GameObject go = AssetDatabase.LoadAssetAtPath(path); var skm = go.GetComponentInChildren(); if(!skm) { if(!go.GetComponentInChildren()) { warning_list.Add(path); return; } } _infoList.Add(info); var fullPath = path.Replace("Assets", Application.dataPath) + ".meta"; var temp = File.ReadAllBytes(fullPath); ModelImporter mi = (ModelImporter)MovieImporter.GetAtPath(path); mi.isReadable = true; mi.optimizeGameObjects = false; EditorUtility.SetDirty(mi); mi.SaveAndReimport(); AssetDatabase.SaveAssets(); if(skm == null) { var skm2 = go.GetComponentInChildren(); if(skm2) { var mesh = skm2.sharedMesh; info.vertsCount = mesh.vertexCount; info.trisCount = mesh.triangles.Length / 3; info.bonesCount = 0; } else { _infoList.Remove(info); warning_list.Add(path); } } else { var mesh = skm.sharedMesh; info.vertsCount = mesh.vertexCount; info.trisCount = mesh.triangles.Length / 3; info.bonesCount = skm.bones.Length; } //Debug.Log(mesh.vertexCount); //Debug.Log(mesh.triangles.Length / 3); //Debug.Log("骨骼数量 " + go.GetComponentInChildren().bones.Length); mi.isReadable = false; mi.optimizeGameObjects = true; EditorUtility.SetDirty(mi); mi.SaveAndReimport(); //AssetDatabase.Refresh(); File.Delete(fullPath); File.WriteAllBytes(fullPath, temp); } void OnSelectionChange() { } private static void Init() { _targetPic = null; instance = EditorWindow.GetWindow("选项"); _pathRoot = "Assets/LuaFramework/AssetBundleRes/scene";//object/role/res/model_clothe_101000/model/model_clothe_101000.fbx instance.position = new Rect(new Vector2(604, 290), new Vector2(650, 450)); } }