源战役客户端
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

428 行
13 KiB

  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEngine.UI;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Text;
  7. using System.IO;
  8. using System.Drawing;
  9. using System.Text.RegularExpressions;
  10. using System;
  11. public class ModelChecker : EditorWindow
  12. {
  13. private static ModelChecker instance;
  14. List<ModelInfo> _infoList = new List<ModelInfo>();
  15. static Texture2D _targetPic;
  16. static string _pathRoot;
  17. static float _alpha_cut_off = 0f;
  18. static int _horizontalSpace = 0;
  19. static int _verticalSpace = 0;
  20. static int _rate = 200;
  21. static int _rateImage = 1;
  22. static int _foreceHight = 23;
  23. static string splitChar = "\t";
  24. static string _ignore = "Tools,Fonts,terrain,effect,action,weapon";
  25. static string[] formatOption = new string[] { "CSV", "xls", "txt" };
  26. static int indexOfFormat;
  27. static string[] sortKey = new string[] { "骨骼数", "面数" ,"顶点数"};
  28. static int indexOfSortKey;
  29. static string[] sortType = new string[] { "升序", "降序" };
  30. static int indexOfSortType = 0;
  31. static SaveType _saveType = SaveType.csv;
  32. static bool _ignore_effect = false;
  33. static Encoding ENCODING = Encoding.GetEncoding("GB2312");
  34. static string titleStr;
  35. static bool _isCheckEmpty = true;
  36. static string[] _ignore_list;
  37. static string des_end_str; //输出文件的后缀名
  38. static List<string> error_list = new List<string>();
  39. static List<string> warning_list = new List<string>();
  40. static string _guiChecker;
  41. static int _checkCount=10000;
  42. bool _tog;
  43. bool _tog2;
  44. bool _tog3;
  45. [MenuItem("Tools/检查模型")]
  46. static void ShowExcelTools()
  47. {
  48. Init();
  49. instance.Show();
  50. }
  51. enum SaveType
  52. {
  53. csv = 0,
  54. xls,
  55. txt,
  56. }
  57. void OnGUI()
  58. {
  59. DrawOptions();
  60. }
  61. static bool Get2Flag(int num)
  62. {
  63. if (num < 1) return false;
  64. return (num & num - 1) == 0;
  65. }
  66. private void DrawOptions()
  67. {
  68. _pathRoot = EditorGUILayout.TextField("指定目录", _pathRoot);
  69. _ignore = EditorGUILayout.TextField("忽略目录关键字", _ignore);
  70. EditorGUILayout.HelpBox("检查的时候会忽略有上面关键字的目录,用逗号‘,’分割", MessageType.Info);
  71. _ignore_list = _ignore.Split(',');
  72. if (GUILayout.Button("scene目录"))
  73. {
  74. _pathRoot = "Assets/LuaFramework/AssetBundleRes/scene";
  75. }
  76. if (GUILayout.Button("资源目录"))
  77. {
  78. _pathRoot = "Assets/LuaFramework/AssetBundleRes";
  79. }
  80. EditorGUILayout.Space();
  81. EditorGUILayout.Space();
  82. indexOfFormat = EditorGUILayout.Popup("储存格式", indexOfFormat, formatOption);
  83. _saveType = (SaveType)indexOfFormat;
  84. if (_saveType == SaveType.csv)
  85. {
  86. splitChar = ",";
  87. des_end_str = ".csv";
  88. }
  89. else if (_saveType == SaveType.xls)
  90. {
  91. splitChar = "\t";
  92. des_end_str = ".xls";
  93. }
  94. else if (_saveType == SaveType.txt)
  95. {
  96. splitChar = "\r\n";
  97. des_end_str = ".txt";
  98. }
  99. indexOfSortKey = EditorGUILayout.Popup("排序关键字", indexOfSortKey, sortKey);
  100. indexOfSortType = EditorGUILayout.Popup("排序类型", indexOfSortType, sortType);
  101. EditorGUILayout.Space();
  102. EditorGUILayout.Space();
  103. titleStr = "骨骼数" + splitChar + "定点数" + splitChar + "三角面数" + splitChar + "文件路径";// + splitChar + "是否有空余像素" + splitChar + "非空范围X" + splitChar + "非空范围Y" + splitChar + "特效文件NPOT" + splitChar + "路径";
  104. _rate = EditorGUILayout.IntField("查找文件速度(文件数/帧)", _rate);
  105. EditorGUILayout.IntField("检查文件速度(文件数/帧)", 1);
  106. EditorGUILayout.HelpBox("因为算法原因,只能一个个检查,无法更改", MessageType.Info);
  107. if (GUILayout.Button("转换"))
  108. {
  109. EditorCoroutineRunner.StartEditorCoroutine(Conver());
  110. }
  111. EditorGUILayout.Space();
  112. EditorGUILayout.Space();
  113. EditorGUILayout.Space();
  114. EditorGUILayout.Space();
  115. EditorGUILayout.HelpBox("-----------------------------------以下测试用-------------------------------------",MessageType.Info);
  116. _guiChecker = EditorGUILayout.TextField("GUID", _guiChecker);
  117. if(GUILayout.Button("GUID转换地址"))
  118. {
  119. Debug.LogError(AssetDatabase.GUIDToAssetPath(_guiChecker));
  120. }
  121. _checkCount = EditorGUILayout.IntField("最多检查文件数", _checkCount);
  122. }
  123. class ModelInfo
  124. {
  125. public string filePath;
  126. public int vertsCount;
  127. public int trisCount;
  128. public int bonesCount;
  129. public ModelInfo(string clearPath)
  130. {
  131. filePath = clearPath;
  132. }
  133. public string GetInfo()
  134. {
  135. string str = "";
  136. str += bonesCount + splitChar;
  137. str += vertsCount + splitChar;
  138. str += trisCount + splitChar;
  139. str += filePath + splitChar;
  140. //str += "\n";
  141. return str;
  142. }
  143. }
  144. int CompareDinosBySize(ModelInfo t1, ModelInfo t2)
  145. {
  146. if(indexOfSortKey == 0)
  147. {
  148. if(indexOfSortType == 0)
  149. {
  150. return t1.bonesCount - t2.bonesCount;
  151. }
  152. else
  153. {
  154. return t2.bonesCount - t1.bonesCount;
  155. }
  156. }
  157. else if(indexOfSortKey == 1)
  158. {
  159. if(indexOfSortType == 0)
  160. {
  161. return t1.trisCount - t2.trisCount;
  162. }
  163. else
  164. {
  165. return t2.trisCount - t1.trisCount;
  166. }
  167. }
  168. else if(indexOfSortKey == 2)
  169. {
  170. if (indexOfSortType == 0)
  171. {
  172. return t1.vertsCount - t2.vertsCount;
  173. }
  174. else
  175. {
  176. return t2.vertsCount - t1.vertsCount;
  177. }
  178. }
  179. return 0;
  180. }
  181. bool IsIgonrePath(string path)
  182. {
  183. foreach (var flag in _ignore_list)
  184. {
  185. if (path.ToLower().Contains(flag.ToLower()))
  186. {
  187. return true;
  188. }
  189. }
  190. return false;
  191. }
  192. IEnumerator Conver()
  193. {
  194. string dateStr = DateTime.Now.Hour.ToString() + "_" + DateTime.Now.Minute.ToString() + "_" + DateTime.Now.Second.ToString();
  195. string newDir = Application.dataPath.Replace("Assets", "") + "/model_output_" + dateStr + des_end_str;
  196. try
  197. {
  198. if(File.Exists(newDir))
  199. {
  200. var test = File.Open(newDir, FileMode.Open);
  201. test.Close();
  202. test.Dispose();
  203. }
  204. }
  205. catch (IOException exp)
  206. {
  207. EditorUtility.DisplayDialog("提示", "错误,请先关闭写入目录的文件 ", "好的呢", "");
  208. Debug.LogError(exp);
  209. yield break;
  210. }
  211. var files = Directory.GetFiles(_pathRoot.Replace("Assets", Application.dataPath), "*.fbx*", SearchOption.AllDirectories);
  212. //var files2 = Directory.GetFiles(_pathRoot.Replace("Assets", Application.dataPath), "*.FBX*", SearchOption.AllDirectories);
  213. List<string> modelPath = new List<string>();
  214. float count = 0;
  215. foreach (var file in files)
  216. {
  217. count++;
  218. if (count % _rate == 0)
  219. {
  220. yield return 1;
  221. }
  222. if (IsIgonrePath(file))
  223. {
  224. continue;
  225. }
  226. if (file.ToLower().EndsWith(".fbx") && !file.ToLower().Contains("@"))
  227. {
  228. var clearPaht = file.Replace(Application.dataPath,"Assets");
  229. modelPath.Add(clearPaht);
  230. if (modelPath.Count > _checkCount)
  231. {
  232. break;
  233. }
  234. EditorUtility.DisplayProgressBar("查找文件中的FBX···"+ modelPath.Count, file, count / files.Length);
  235. }
  236. }
  237. if(!EditorUtility.DisplayDialog("提示", "一共查找到"+ modelPath.Count+ "个文件,是否继续\n因为只能一个个检查,所以数量大会很慢哦\n\n520个文件大概5到10分钟", "继续", "取消"))
  238. {
  239. EditorUtility.ClearProgressBar();
  240. yield break;
  241. }
  242. error_list.Clear();
  243. warning_list.Clear();
  244. _infoList.Clear();
  245. count = 0;
  246. foreach (var singPath in modelPath)
  247. {
  248. count++;
  249. //if(count > 180 && count < 200)
  250. //{
  251. //}
  252. //else
  253. //{
  254. // continue;
  255. //}
  256. try
  257. {
  258. CheckSinglModel(singPath);
  259. }
  260. catch (Exception exp)
  261. {
  262. error_list.Add(singPath);
  263. Debug.LogError(singPath + "\n\n" + exp);
  264. }
  265. if (count % _rateImage == 0)
  266. {
  267. yield return 1;
  268. }
  269. EditorUtility.DisplayProgressBar("检查模型中···(共" + modelPath.Count + "个)" + count + "/" + modelPath.Count, singPath, count / modelPath.Count);
  270. }
  271. _infoList.Sort(CompareDinosBySize);
  272. count = 0;
  273. List<string> str = new List<string>();
  274. str.Add(titleStr);
  275. foreach (var info in _infoList)
  276. {
  277. count++;
  278. str.Add(info.GetInfo());
  279. //if (count % _rateImage * 30 == 0)
  280. //{
  281. // yield return 1;
  282. //}
  283. EditorUtility.DisplayProgressBar("整理文件中···", "不想告诉你当前进度·····", count / _infoList.Count);
  284. }
  285. str.Add("以下文件出错");
  286. str.AddRange(error_list);
  287. str.Add("以下文件读取时候出现异常,可能出错");
  288. str.AddRange(warning_list);
  289. EditorUtility.DisplayProgressBar("写入文件中···", "", 0);
  290. if (_infoList.Count > 0)
  291. {
  292. try
  293. {
  294. File.WriteAllLines(newDir, str.ToArray(), ENCODING);
  295. }
  296. catch (IOException exp)
  297. {
  298. EditorUtility.ClearProgressBar();
  299. EditorUtility.DisplayDialog("提示", "错误,请先关闭写入目录的文件 ", "好的呢", "");
  300. yield break;
  301. }
  302. }
  303. EditorUtility.DisplayDialog("提示", "扫描完成", "GOOD", "");
  304. EditorUtility.ClearProgressBar();
  305. AssetDatabase.Refresh();
  306. }
  307. void CheckSinglModel(string path)
  308. {
  309. path = path.Replace(@"\","/");
  310. if(path.Contains("@"))
  311. {
  312. return;
  313. }
  314. ModelInfo info = new ModelInfo(path);
  315. GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
  316. var skm = go.GetComponentInChildren<SkinnedMeshRenderer>();
  317. if(!skm)
  318. {
  319. if(!go.GetComponentInChildren<MeshFilter>())
  320. {
  321. warning_list.Add(path);
  322. return;
  323. }
  324. }
  325. _infoList.Add(info);
  326. var fullPath = path.Replace("Assets", Application.dataPath) + ".meta";
  327. var temp = File.ReadAllBytes(fullPath);
  328. ModelImporter mi = (ModelImporter)MovieImporter.GetAtPath(path);
  329. mi.isReadable = true;
  330. mi.optimizeGameObjects = false;
  331. EditorUtility.SetDirty(mi);
  332. mi.SaveAndReimport();
  333. AssetDatabase.SaveAssets();
  334. if(skm == null)
  335. {
  336. var skm2 = go.GetComponentInChildren<MeshFilter>();
  337. if(skm2)
  338. {
  339. var mesh = skm2.sharedMesh;
  340. info.vertsCount = mesh.vertexCount;
  341. info.trisCount = mesh.triangles.Length / 3;
  342. info.bonesCount = 0;
  343. }
  344. else
  345. {
  346. _infoList.Remove(info);
  347. warning_list.Add(path);
  348. }
  349. }
  350. else
  351. {
  352. var mesh = skm.sharedMesh;
  353. info.vertsCount = mesh.vertexCount;
  354. info.trisCount = mesh.triangles.Length / 3;
  355. info.bonesCount = skm.bones.Length;
  356. }
  357. //Debug.Log(mesh.vertexCount);
  358. //Debug.Log(mesh.triangles.Length / 3);
  359. //Debug.Log("骨骼数量 " + go.GetComponentInChildren<SkinnedMeshRenderer>().bones.Length);
  360. mi.isReadable = false;
  361. mi.optimizeGameObjects = true;
  362. EditorUtility.SetDirty(mi);
  363. mi.SaveAndReimport();
  364. //AssetDatabase.Refresh();
  365. File.Delete(fullPath);
  366. File.WriteAllBytes(fullPath, temp);
  367. }
  368. void OnSelectionChange()
  369. {
  370. }
  371. private static void Init()
  372. {
  373. _targetPic = null;
  374. instance = EditorWindow.GetWindow<ModelChecker>("选项");
  375. _pathRoot = "Assets/LuaFramework/AssetBundleRes/scene";//object/role/res/model_clothe_101000/model/model_clothe_101000.fbx
  376. instance.position = new Rect(new Vector2(604, 290), new Vector2(650, 450));
  377. }
  378. }