MB3_MeshBakerEditorWindowAddObjectsTab.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. //----------------------------------------------
  2. // MeshBaker
  3. // Copyright © 2011-2012 Ian Deane
  4. //----------------------------------------------
  5. using UnityEditor;
  6. using UnityEngine;
  7. using System;
  8. using System.Reflection;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using DigitalOpus.MB.Core;
  12. namespace DigitalOpus.MB.MBEditor
  13. {
  14. public class MB3_MeshBakerEditorWindowAddObjectsTab : MB3_MeshBakerEditorWindowInterface
  15. {
  16. static string[] LODLevelLabels = new string[]
  17. {
  18. "All LOD Levels", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
  19. };
  20. static int[] LODLevelValues = new int[]
  21. {
  22. -1,0,1,2,3,4,5,6,7,8,9
  23. };
  24. public MB3_MeshBakerRoot _target = null;
  25. public MonoBehaviour target
  26. {
  27. get { return _target; }
  28. set { _target = (MB3_MeshBakerRoot)value; }
  29. }
  30. GameObject targetGO = null;
  31. GameObject oldTargetGO = null;
  32. MB3_TextureBaker textureBaker;
  33. MB3_MeshBaker meshBaker;
  34. UnityEngine.Object[] targs = new UnityEngine.Object[1];
  35. SerializedObject serializedObject;
  36. GUIContent GUIContentRegExpression = new GUIContent("Matches Regular Expression", @"A valid # regular express. Examples:" + "\n\n" +
  37. @" ([A-Za-z0-9\-]+)(LOD1) matches one or more chars,numbers and hyphen ending with LOD1." + "\n\n" +
  38. @" (Grass)([A-Za-z0-9\-\(\) ]+) matches the string 'Grass' followed by characters, numbers, hyphen, brackets or space." + "\n\n");
  39. string helpBoxString = "";
  40. string regExParseError = "";
  41. bool onlyStaticObjects = false;
  42. bool onlyEnabledObjects = false;
  43. bool excludeMeshesWithOBuvs = true;
  44. bool excludeMeshesAlreadyAddedToBakers = true;
  45. int lodLevelToInclude = -1;
  46. int lightmapIndex = -2;
  47. string searchRegEx = "";
  48. Material shaderMat = null;
  49. Material mat = null;
  50. bool tbFoldout = false;
  51. bool mbFoldout = false;
  52. MB3_MeshBakerEditorInternal mbe = new MB3_MeshBakerEditorInternal();
  53. MB3_TextureBakerEditorInternal tbe = new MB3_TextureBakerEditorInternal();
  54. public void OnEnable()
  55. {
  56. if (textureBaker != null)
  57. {
  58. serializedObject = new SerializedObject(textureBaker);
  59. tbe.OnEnable(serializedObject);
  60. }
  61. else if (meshBaker != null)
  62. {
  63. serializedObject = new SerializedObject(meshBaker);
  64. mbe.OnEnable(serializedObject);
  65. }
  66. }
  67. public void OnDisable()
  68. {
  69. tbe.OnDisable();
  70. mbe.OnDisable();
  71. }
  72. public void drawTabAddObjectsToBakers()
  73. {
  74. if (helpBoxString == null) helpBoxString = "";
  75. EditorGUILayout.HelpBox("To add, select one or more objects in the hierarchy view. Child Game Objects with MeshRender or SkinnedMeshRenderer will be added. Use the fields below to filter what is added." +
  76. "To remove, use the fields below to filter what is removed.\n" + helpBoxString, UnityEditor.MessageType.None);
  77. target = (MB3_MeshBakerRoot)EditorGUILayout.ObjectField("Target to add objects to", target, typeof(MB3_MeshBakerRoot), true);
  78. if (target != null)
  79. {
  80. targetGO = target.gameObject;
  81. }
  82. else
  83. {
  84. targetGO = null;
  85. }
  86. if (targetGO != oldTargetGO && targetGO != null)
  87. {
  88. textureBaker = targetGO.GetComponent<MB3_TextureBaker>();
  89. meshBaker = targetGO.GetComponent<MB3_MeshBaker>();
  90. tbe = new MB3_TextureBakerEditorInternal();
  91. mbe = new MB3_MeshBakerEditorInternal();
  92. oldTargetGO = targetGO;
  93. if (textureBaker != null)
  94. {
  95. serializedObject = new SerializedObject(textureBaker);
  96. tbe.OnEnable(serializedObject);
  97. }
  98. else if (meshBaker != null)
  99. {
  100. serializedObject = new SerializedObject(meshBaker);
  101. mbe.OnEnable(serializedObject);
  102. }
  103. }
  104. EditorGUIUtility.labelWidth = 300;
  105. onlyStaticObjects = EditorGUILayout.Toggle("Only Static Objects", onlyStaticObjects);
  106. onlyEnabledObjects = EditorGUILayout.Toggle("Only Enabled Objects", onlyEnabledObjects);
  107. excludeMeshesWithOBuvs = EditorGUILayout.Toggle("Exclude meshes with out-of-bounds UVs", excludeMeshesWithOBuvs);
  108. excludeMeshesAlreadyAddedToBakers = EditorGUILayout.Toggle("Exclude GameObjects already added to bakers", excludeMeshesAlreadyAddedToBakers);
  109. lodLevelToInclude = EditorGUILayout.IntPopup("Only include objects on LOD Level", lodLevelToInclude, LODLevelLabels, LODLevelValues);
  110. mat = (Material)EditorGUILayout.ObjectField("Using Material", mat, typeof(Material), true);
  111. shaderMat = (Material)EditorGUILayout.ObjectField("Using Shader", shaderMat, typeof(Material), true);
  112. string[] lightmapDisplayValues = new string[257];
  113. int[] lightmapValues = new int[257];
  114. lightmapValues[0] = -2;
  115. lightmapValues[1] = -1;
  116. lightmapDisplayValues[0] = "don't filter on lightmapping";
  117. lightmapDisplayValues[1] = "not lightmapped";
  118. for (int i = 2; i < lightmapDisplayValues.Length; i++)
  119. {
  120. lightmapDisplayValues[i] = "" + i;
  121. lightmapValues[i] = i;
  122. }
  123. EditorGUILayout.BeginHorizontal();
  124. EditorGUILayout.LabelField("Using Lightmap Index ");
  125. lightmapIndex = EditorGUILayout.IntPopup(lightmapIndex,
  126. lightmapDisplayValues,
  127. lightmapValues);
  128. EditorGUILayout.EndHorizontal();
  129. if (regExParseError != null && regExParseError.Length > 0)
  130. {
  131. EditorGUILayout.HelpBox("Error In Regular Expression:\n" + regExParseError, MessageType.Error);
  132. }
  133. searchRegEx = EditorGUILayout.TextField(GUIContentRegExpression, searchRegEx);
  134. EditorGUILayout.Separator();
  135. EditorGUILayout.BeginHorizontal();
  136. if (GUILayout.Button("Add Selected Meshes To Target"))
  137. {
  138. addSelectedObjects();
  139. }
  140. if (GUILayout.Button("Remove Matching Meshes From Target"))
  141. {
  142. removeSelectedObjects();
  143. }
  144. EditorGUILayout.EndHorizontal();
  145. if (textureBaker != null)
  146. {
  147. MB_EditorUtil.DrawSeparator();
  148. tbFoldout = EditorGUILayout.Foldout(tbFoldout, "Texture Baker");
  149. if (tbFoldout)
  150. {
  151. if (targs == null) targs = new UnityEngine.Object[1];
  152. targs[0] = textureBaker;
  153. tbe.DrawGUI(serializedObject, (MB3_TextureBaker)textureBaker, targs, typeof(MB3_MeshBakerEditorWindow));
  154. }
  155. }
  156. if (meshBaker != null)
  157. {
  158. MB_EditorUtil.DrawSeparator();
  159. mbFoldout = EditorGUILayout.Foldout(mbFoldout, "Mesh Baker");
  160. if (mbFoldout)
  161. {
  162. if (targs == null) targs = new UnityEngine.Object[1];
  163. targs[0] = meshBaker;
  164. mbe.DrawGUI(serializedObject, (MB3_MeshBaker)meshBaker, targs, typeof(MB3_MeshBakerEditorWindow));
  165. }
  166. }
  167. }
  168. List<GameObject> GetFilteredList(bool addingObjects)
  169. {
  170. List<GameObject> newMomObjs = new List<GameObject>();
  171. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
  172. if (mom == null)
  173. {
  174. Debug.LogError("Must select a target MeshBaker");
  175. return newMomObjs;
  176. }
  177. GameObject dontAddMe = null;
  178. Renderer r = MB_Utility.GetRenderer(mom.gameObject);
  179. if (r != null)
  180. { //make sure that this MeshBaker object is not in list
  181. dontAddMe = r.gameObject;
  182. }
  183. MB3_MeshBakerRoot[] allBakers = GameObject.FindObjectsOfType<MB3_MeshBakerRoot>();
  184. HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
  185. if (addingObjects)
  186. {
  187. for (int i = 0; i < allBakers.Length; i++)
  188. {
  189. List<GameObject> objsToCombine = allBakers[i].GetObjectsToCombine();
  190. for (int j = 0; j < objsToCombine.Count; j++)
  191. {
  192. if (objsToCombine[j] != null) objectsAlreadyIncludedInBakers.Add(objsToCombine[j]);
  193. }
  194. }
  195. }
  196. GameObject[] gos = Selection.gameObjects;
  197. if (gos.Length == 0)
  198. {
  199. Debug.LogWarning("No objects selected in hierarchy view. Nothing added. Try selecting some objects.");
  200. return newMomObjs;
  201. }
  202. List<GameObject> mrs = new List<GameObject>();
  203. for (int i = 0; i < gos.Length; i++)
  204. {
  205. GameObject go = gos[i];
  206. Renderer[] rs = go.GetComponentsInChildren<Renderer>(true);
  207. for (int j = 0; j < rs.Length; j++)
  208. {
  209. if (rs[j] is MeshRenderer || rs[j] is SkinnedMeshRenderer)
  210. {
  211. mrs.Add(rs[j].gameObject);
  212. }
  213. }
  214. }
  215. newMomObjs = FilterList(mrs, objectsAlreadyIncludedInBakers, dontAddMe, addingObjects);
  216. return newMomObjs;
  217. }
  218. int GetLODLevelForRenderer(Renderer r)
  219. {
  220. if (r != null)
  221. {
  222. LODGroup lodGroup = r.GetComponentInParent<LODGroup>();
  223. if (lodGroup != null)
  224. {
  225. LOD[] lods = lodGroup.GetLODs();
  226. for (int lodIdx = 0; lodIdx < lods.Length; lodIdx++)
  227. {
  228. Renderer[] rs = lods[lodIdx].renderers;
  229. for (int j = 0; j < rs.Length; j++)
  230. {
  231. if (rs[j] == r)
  232. {
  233. return lodIdx;
  234. }
  235. }
  236. }
  237. }
  238. }
  239. return 0;
  240. }
  241. List<GameObject> FilterList(List<GameObject> mrss,
  242. HashSet<GameObject> objectsAlreadyIncludedInBakers,
  243. GameObject dontAddMe,
  244. bool addingObjects)
  245. {
  246. int numInSelection = 0;
  247. int numStaticExcluded = 0;
  248. int numEnabledExcluded = 0;
  249. int numLightmapExcluded = 0;
  250. int numLodLevelExcluded = 0;
  251. int numOBuvExcluded = 0;
  252. int numMatExcluded = 0;
  253. int numShaderExcluded = 0;
  254. int numRegExExcluded = 0;
  255. int numAlreadyIncludedExcluded = 0;
  256. System.Text.RegularExpressions.Regex regex = null;
  257. if (searchRegEx != null && searchRegEx.Length > 0)
  258. {
  259. try
  260. {
  261. regex = new System.Text.RegularExpressions.Regex(searchRegEx);
  262. regExParseError = "";
  263. }
  264. catch (Exception ex)
  265. {
  266. regExParseError = ex.Message;
  267. }
  268. }
  269. Dictionary<int, MB_Utility.MeshAnalysisResult> meshAnalysisResultsCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>(); //cache results
  270. List<GameObject> newMomObjs = new List<GameObject>();
  271. for (int j = 0; j < mrss.Count; j++)
  272. {
  273. if (mrss[j] == null)
  274. {
  275. continue;
  276. }
  277. Renderer mrs = mrss[j].GetComponent<Renderer>();
  278. if (mrs is MeshRenderer || mrs is SkinnedMeshRenderer)
  279. {
  280. if (mrs.GetComponent<TextMesh>() != null)
  281. {
  282. continue; //don't add TextMeshes
  283. }
  284. numInSelection++;
  285. if (!newMomObjs.Contains(mrs.gameObject))
  286. {
  287. bool addMe = true;
  288. if (!mrs.gameObject.isStatic && onlyStaticObjects)
  289. {
  290. numStaticExcluded++;
  291. addMe = false;
  292. continue;
  293. }
  294. if ((!mrs.enabled || !mrs.gameObject.activeInHierarchy) && onlyEnabledObjects)
  295. {
  296. numEnabledExcluded++;
  297. addMe = false;
  298. continue;
  299. }
  300. if (lightmapIndex != -2)
  301. {
  302. if (mrs.lightmapIndex != lightmapIndex)
  303. {
  304. numLightmapExcluded++;
  305. addMe = false;
  306. continue;
  307. }
  308. }
  309. if (lodLevelToInclude == -1)
  310. {
  311. // not filtering on LODLevel
  312. }
  313. else
  314. {
  315. if (GetLODLevelForRenderer(mrs) != lodLevelToInclude)
  316. {
  317. numLodLevelExcluded++;
  318. addMe = false;
  319. continue;
  320. }
  321. }
  322. // only do this check when adding objects. If removing objects shouldn't do it
  323. if (addingObjects &&
  324. excludeMeshesAlreadyAddedToBakers &&
  325. objectsAlreadyIncludedInBakers.Contains(mrs.gameObject))
  326. {
  327. numAlreadyIncludedExcluded++;
  328. addMe = false;
  329. continue;
  330. }
  331. Mesh mm = MB_Utility.GetMesh(mrs.gameObject);
  332. if (mm != null)
  333. {
  334. MB_Utility.MeshAnalysisResult mar;
  335. if (!meshAnalysisResultsCache.TryGetValue(mm.GetInstanceID(), out mar))
  336. {
  337. MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
  338. meshAnalysisResultsCache.Add(mm.GetInstanceID(), mar);
  339. }
  340. if (mar.hasOutOfBoundsUVs && excludeMeshesWithOBuvs)
  341. {
  342. numOBuvExcluded++;
  343. addMe = false;
  344. continue;
  345. }
  346. }
  347. if (shaderMat != null)
  348. {
  349. Material[] nMats = mrs.sharedMaterials;
  350. bool usesShader = false;
  351. foreach (Material nMat in nMats)
  352. {
  353. if (nMat != null && nMat.shader == shaderMat.shader)
  354. {
  355. usesShader = true;
  356. }
  357. }
  358. if (!usesShader)
  359. {
  360. numShaderExcluded++;
  361. addMe = false;
  362. continue;
  363. }
  364. }
  365. if (mat != null)
  366. {
  367. Material[] nMats = mrs.sharedMaterials;
  368. bool usesMat = false;
  369. foreach (Material nMat in nMats)
  370. {
  371. if (nMat == mat)
  372. {
  373. usesMat = true;
  374. }
  375. }
  376. if (!usesMat)
  377. {
  378. numMatExcluded++;
  379. addMe = false;
  380. continue;
  381. }
  382. }
  383. if (regex != null)
  384. {
  385. if (!regex.IsMatch(mrs.gameObject.name))
  386. {
  387. numRegExExcluded++;
  388. addMe = false;
  389. continue;
  390. }
  391. }
  392. if (addMe && mrs.gameObject != dontAddMe)
  393. {
  394. if (!newMomObjs.Contains(mrs.gameObject))
  395. {
  396. newMomObjs.Add(mrs.gameObject);
  397. }
  398. }
  399. }
  400. }
  401. }
  402. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  403. //sb.AppendFormat("Total objects in selection {0}\n", numInSelection);
  404. //Debug.Log( "Total objects in selection " + numInSelection);
  405. if (numStaticExcluded > 0)
  406. {
  407. sb.AppendFormat(" {0} objects were excluded because they were not static\n", numStaticExcluded);
  408. Debug.Log(numStaticExcluded + " objects were excluded because they were not static\n");
  409. }
  410. if (numEnabledExcluded > 0)
  411. {
  412. sb.AppendFormat(" {0} objects were excluded because they were disabled\n", numEnabledExcluded);
  413. Debug.Log(numEnabledExcluded + " objects were excluded because they were disabled\n");
  414. }
  415. if (numOBuvExcluded > 0)
  416. {
  417. sb.AppendFormat(" {0} objects were excluded because they were had out of bounds uvs\n", numOBuvExcluded);
  418. Debug.Log(numOBuvExcluded + " objects were excluded because they had out of bounds uvs\n");
  419. }
  420. if (numLightmapExcluded > 0)
  421. {
  422. sb.AppendFormat(" {0} objects were excluded because they did not match lightmap filter.\n", numLightmapExcluded);
  423. Debug.Log(numLightmapExcluded + " objects did not match lightmap filter.\n");
  424. }
  425. if (numLodLevelExcluded > 0)
  426. {
  427. sb.AppendFormat(" {0} objects were excluded because they did not match the selected LOD level filter.\n", numLodLevelExcluded);
  428. Debug.Log(numLodLevelExcluded + " objects did not match LOD level filter.\n");
  429. }
  430. if (numShaderExcluded > 0)
  431. {
  432. sb.AppendFormat(" {0} objects were excluded because they did not use the selected shader.\n", numShaderExcluded);
  433. Debug.Log(numShaderExcluded + " objects were excluded because they did not use the selected shader.\n");
  434. }
  435. if (numMatExcluded > 0)
  436. {
  437. sb.AppendFormat(" {0} objects were excluded because they did not use the selected material.\n", numMatExcluded);
  438. Debug.Log(numMatExcluded + " objects were excluded because they did not use the selected material.\n");
  439. }
  440. if (numRegExExcluded > 0)
  441. {
  442. sb.AppendFormat(" {0} objects were excluded because they did not match the regular expression.\n", numRegExExcluded);
  443. Debug.Log(numRegExExcluded + " objects were excluded because they did not match the regular expression.\n");
  444. }
  445. if (numAlreadyIncludedExcluded > 0)
  446. {
  447. sb.AppendFormat(" {0} objects were excluded because they did were already included in other bakers.\n", numAlreadyIncludedExcluded);
  448. Debug.Log(numAlreadyIncludedExcluded + " objects were excluded because they did were already included in other bakers.\n");
  449. }
  450. helpBoxString = sb.ToString();
  451. return newMomObjs;
  452. }
  453. void removeSelectedObjects()
  454. {
  455. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
  456. if (mom == null)
  457. {
  458. Debug.LogError("Must select a target MeshBaker");
  459. return;
  460. }
  461. List<GameObject> objsToCombine = mom.GetObjectsToCombine();
  462. HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
  463. GameObject dontAddMe = null;
  464. Renderer r = MB_Utility.GetRenderer(mom.gameObject);
  465. if (r != null)
  466. { //make sure that this MeshBaker object is not in list
  467. dontAddMe = r.gameObject;
  468. }
  469. List<GameObject> objsSelectedMatchingFilter = GetFilteredList(addingObjects:false);
  470. Debug.Log("Matching filter " + objsSelectedMatchingFilter.Count);
  471. List<GameObject> objsToRemove = new List<GameObject>();
  472. for (int i = 0; i < objsSelectedMatchingFilter.Count; i++)
  473. {
  474. if (objsToCombine.Contains(objsSelectedMatchingFilter[i]))
  475. {
  476. objsToRemove.Add(objsSelectedMatchingFilter[i]);
  477. }
  478. }
  479. MBVersionEditor.RegisterUndo(mom, "Remove Objects");
  480. for (int i = 0; i < objsToRemove.Count; i++)
  481. {
  482. objsToCombine.Remove(objsToRemove[i]);
  483. }
  484. SerializedObject so = new SerializedObject(mom);
  485. so.SetIsDifferentCacheDirty();
  486. Debug.Log("Removed " + objsToRemove.Count + " objects from " + mom.name);
  487. helpBoxString += String.Format("\nRemoved {0} objects from {1}", objsToRemove.Count, mom.name);
  488. }
  489. void addSelectedObjects()
  490. {
  491. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
  492. if (mom == null)
  493. {
  494. Debug.LogError("Must select a target MeshBaker to add objects to");
  495. return;
  496. }
  497. List<GameObject> newMomObjs = GetFilteredList(addingObjects:true);
  498. MBVersionEditor.RegisterUndo(mom, "Add Objects");
  499. List<GameObject> momObjs = mom.GetObjectsToCombine();
  500. int numAdded = 0;
  501. int numAlreadyInList = 0;
  502. for (int i = 0; i < newMomObjs.Count; i++)
  503. {
  504. if (!momObjs.Contains(newMomObjs[i]))
  505. {
  506. momObjs.Add(newMomObjs[i]);
  507. numAdded++;
  508. }
  509. else
  510. {
  511. numAlreadyInList++;
  512. }
  513. }
  514. SerializedObject so = new SerializedObject(mom);
  515. so.SetIsDifferentCacheDirty();
  516. if (numAlreadyInList > 0)
  517. {
  518. Debug.Log(String.Format("Skipped adding {0} objects to Target because these objects had already been added to this Target. ", numAlreadyInList));
  519. }
  520. if (numAdded == 0)
  521. {
  522. Debug.LogWarning("Added 0 objects. Make sure some or all objects are selected in the hierarchy view. Also check ths 'Only Static Objects', 'Using Material' and 'Using Shader' settings");
  523. }
  524. else
  525. {
  526. Debug.Log(string.Format("Added {0} objects to {1}. ", numAdded, mom.name));
  527. }
  528. helpBoxString += String.Format("\nAdded {0} objects to {1}", numAdded, mom.name);
  529. }
  530. }
  531. }