MB3_MeshBakerEditorWindow.cs 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  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. public class MB3_MeshBakerEditorWindow : EditorWindow, MB3_MeshBakerEditorWindowInterface
  13. {
  14. static string[] LODLevelLabels = new string[]
  15. {
  16. "All LOD Levels", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
  17. };
  18. static int[] LODLevelValues = new int[]
  19. {
  20. -1,0,1,2,3,4,5,6,7,8,9
  21. };
  22. public MB3_MeshBakerRoot _target = null;
  23. public MonoBehaviour target{
  24. get{ return _target; }
  25. set{ _target = (MB3_MeshBakerRoot) value; }
  26. }
  27. GameObject targetGO = null;
  28. GameObject oldTargetGO = null;
  29. MB3_TextureBaker textureBaker;
  30. MB3_MeshBaker meshBaker;
  31. MB3_MeshBakerGrouperCore textureBakerGrouper;
  32. SerializedObject serializedObject;
  33. bool writeReportFile = false;
  34. GUIContent GUIContentRegExpression = new GUIContent("Matches Regular Expression", @"A valid # regular express. Examples:" + "\n\n" +
  35. @" ([A-Za-z0-9\-]+)(LOD1) matches one or more chars,numbers and hyphen ending with LOD1." + "\n\n" +
  36. @" (Grass)([A-Za-z0-9\-\(\) ]+) matches the string 'Grass' followed by characters, numbers, hyphen, brackets or space." + "\n\n");
  37. string helpBoxString = "";
  38. string regExParseError = "";
  39. bool onlyStaticObjects = false;
  40. bool onlyEnabledObjects = false;
  41. bool excludeMeshesWithOBuvs = true;
  42. bool excludeMeshesAlreadyAddedToBakers = true;
  43. bool splitAtlasesSoMeshesFit = false;
  44. int lodLevelToInclude = -1;
  45. int atlasSize = 4096;
  46. int lightmapIndex = -2;
  47. string searchRegEx = "";
  48. Material shaderMat = null;
  49. Material mat = null;
  50. bool tbFoldout = false;
  51. bool mbFoldout = false;
  52. string generate_AssetsFolder = "";
  53. List<List<GameObjectFilterInfo>> sceneAnalysisResults = new List<List<GameObjectFilterInfo>>();
  54. bool[] sceneAnalysisResultsFoldouts = new bool[0];
  55. MB3_MeshBakerEditorInternal mbe = new MB3_MeshBakerEditorInternal();
  56. MB3_TextureBakerEditorInternal tbe = new MB3_TextureBakerEditorInternal();
  57. const int NUM_FILTERS = 5;
  58. int[] groupByFilterIdxs = new int[NUM_FILTERS];
  59. string[] groupByOptionNames;
  60. IGroupByFilter[] groupByOptionFilters;
  61. Vector2 scrollPos = Vector2.zero;
  62. Vector2 scrollPos2 = Vector2.zero;
  63. int selectedTab = 0;
  64. GUIContent[] tabs = new GUIContent[]{new GUIContent("Analyse Scene & Generate Bakers"),new GUIContent("Search For Meshes To Add")};
  65. GUIContent gc_atlasSize = new GUIContent("Max Atlas Size", "");
  66. GUIContent gc_splitAtlasesSoMeshesFit = new GUIContent("Split Groups If Textures Would Exceed Atlas Size (beta)", "If combining the textures into a single atlas would exceed the maximum atlas size then create multiple atlases. Othersize texture sizes are reduced.");
  67. IGroupByFilter[] filters;
  68. [MenuItem("Window/Mesh Baker")]
  69. static void Init()
  70. {
  71. EditorWindow.GetWindow(typeof(MB3_MeshBakerEditorWindow));
  72. }
  73. void OnGUI()
  74. {
  75. selectedTab = GUILayout.Toolbar(selectedTab,tabs);
  76. scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(position.width), GUILayout.Height(position.height));
  77. if (selectedTab == 0){
  78. drawTabAnalyseScene();
  79. } else {
  80. drawTabAddObjectsToBakers();
  81. }
  82. EditorGUILayout.EndScrollView();
  83. }
  84. void OnEnable()
  85. {
  86. if (textureBaker != null)
  87. {
  88. serializedObject = new SerializedObject(textureBaker);
  89. tbe.OnEnable(serializedObject);
  90. } else if (meshBaker != null)
  91. {
  92. serializedObject = new SerializedObject(meshBaker);
  93. mbe.OnEnable(serializedObject);
  94. }
  95. }
  96. void OnDisable()
  97. {
  98. tbe.OnDisable();
  99. mbe.OnDisable();
  100. }
  101. public static bool InterfaceFilter(Type typeObj, System.Object criteriaObj)
  102. {
  103. return typeObj.ToString() == criteriaObj.ToString();
  104. }
  105. void populateGroupByFilters()
  106. {
  107. string qualifiedInterfaceName = "DigitalOpus.MB.Core.IGroupByFilter";
  108. var interfaceFilter = new TypeFilter(InterfaceFilter);
  109. List<Type> types = new List<Type>();
  110. foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
  111. {
  112. System.Collections.IEnumerable typesIterator = null;
  113. try
  114. {
  115. typesIterator = ass.GetTypes();
  116. }
  117. catch (Exception e)
  118. {
  119. //Debug.Log("The assembly that I could not read types for was: " + ass.GetName());
  120. //suppress error
  121. e.Equals(null);
  122. }
  123. if (typesIterator != null)
  124. {
  125. foreach (Type ty in ass.GetTypes())
  126. {
  127. var myInterfaces = ty.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
  128. if (myInterfaces.Length > 0)
  129. {
  130. types.Add(ty);
  131. }
  132. }
  133. }
  134. }
  135. List<string> filterNames = new List<string>();
  136. List<IGroupByFilter> filters = new List<IGroupByFilter>();
  137. filterNames.Add("None");
  138. filters.Add(null);
  139. foreach (Type tt in types)
  140. {
  141. if (!tt.IsAbstract && !tt.IsInterface)
  142. {
  143. IGroupByFilter instance = (IGroupByFilter)Activator.CreateInstance(tt);
  144. filterNames.Add(instance.GetName());
  145. filters.Add(instance);
  146. }
  147. }
  148. groupByOptionNames = filterNames.ToArray();
  149. groupByOptionFilters = filters.ToArray();
  150. }
  151. void drawTabAnalyseScene(){
  152. //first time we are displaying collect the filters
  153. if (groupByOptionNames == null || groupByOptionNames.Length == 0){
  154. //var types = AppDomain.CurrentDomain.GetAssemblies()
  155. // .SelectMany(s => s.GetTypes())
  156. // .Where(p => type.IsAssignableFrom(p));
  157. populateGroupByFilters();
  158. //set filter initial values
  159. for (int i = 0; i < groupByOptionFilters.Length; i++){
  160. if (groupByOptionFilters[i] is GroupByShader){
  161. groupByFilterIdxs[0] = i;
  162. break;
  163. }
  164. }
  165. for (int i = 0; i < groupByOptionFilters.Length; i++){
  166. if (groupByOptionFilters[i] is GroupByStatic){
  167. groupByFilterIdxs[1] = i;
  168. break;
  169. }
  170. }
  171. for (int i = 0; i < groupByOptionFilters.Length; i++){
  172. if (groupByOptionFilters[i] is GroupByRenderType){
  173. groupByFilterIdxs[2] = i;
  174. break;
  175. }
  176. }
  177. for (int i = 0; i < groupByOptionFilters.Length; i++){
  178. if (groupByOptionFilters[i] is GroupByOutOfBoundsUVs){
  179. groupByFilterIdxs[3] = i;
  180. break;
  181. }
  182. }
  183. groupByFilterIdxs[4] = 0; //none
  184. }
  185. if (groupByFilterIdxs == null || groupByFilterIdxs.Length < NUM_FILTERS){
  186. groupByFilterIdxs = new int[]{
  187. 0,0,0,0,0
  188. };
  189. }
  190. EditorGUILayout.HelpBox("List shaders in scene prints a report to the console of shaders and which objects use them. This is useful for planning which objects to combine.", UnityEditor.MessageType.None);
  191. groupByFilterIdxs[0] = EditorGUILayout.Popup("Group By:",groupByFilterIdxs[0],groupByOptionNames);
  192. for (int i = 1; i < NUM_FILTERS; i++){
  193. groupByFilterIdxs[i] = EditorGUILayout.Popup("Then Group By:",groupByFilterIdxs[i],groupByOptionNames);
  194. }
  195. EditorGUILayout.BeginHorizontal();
  196. float oldLabelWidth = EditorGUIUtility.labelWidth;
  197. EditorGUIUtility.labelWidth = 300;
  198. splitAtlasesSoMeshesFit = EditorGUILayout.Toggle(gc_splitAtlasesSoMeshesFit, splitAtlasesSoMeshesFit);
  199. EditorGUIUtility.labelWidth = oldLabelWidth;
  200. bool enableAtlasField = true;
  201. if (splitAtlasesSoMeshesFit)
  202. {
  203. enableAtlasField = false;
  204. }
  205. EditorGUI.BeginDisabledGroup(enableAtlasField);
  206. atlasSize = EditorGUILayout.IntField(gc_atlasSize, atlasSize);
  207. EditorGUI.EndDisabledGroup();
  208. EditorGUILayout.EndHorizontal();
  209. EditorGUILayout.BeginHorizontal();
  210. if (GUILayout.Button("Select Folder For Combined Material Assets") ){
  211. generate_AssetsFolder = EditorUtility.SaveFolderPanel("Create Combined Material Assets In Folder", "", "");
  212. generate_AssetsFolder = "Assets" + generate_AssetsFolder.Replace(Application.dataPath, "") + "/";
  213. }
  214. EditorGUILayout.LabelField("Folder: " + generate_AssetsFolder);
  215. EditorGUILayout.EndHorizontal();
  216. EditorGUILayout.BeginHorizontal();
  217. if (GUILayout.Button("List Shaders In Scene")){
  218. EditorUtility.DisplayProgressBar("Analysing Scene","",.05f);
  219. try {
  220. listMaterialsInScene();
  221. } catch (Exception ex){
  222. Debug.LogError(ex.StackTrace);
  223. } finally {
  224. EditorUtility.ClearProgressBar();
  225. }
  226. }
  227. if (GUILayout.Button("Bake Every MeshBaker In Scene")){
  228. try{
  229. MB3_TextureBaker[] texBakers = (MB3_TextureBaker[]) FindObjectsOfType(typeof(MB3_TextureBaker));
  230. for (int i = 0; i < texBakers.Length; i++){
  231. texBakers[i].CreateAtlases(updateProgressBar, true, new MB3_EditorMethods());
  232. }
  233. MB3_MeshBakerCommon[] mBakers = (MB3_MeshBakerCommon[]) FindObjectsOfType(typeof(MB3_MeshBakerCommon));
  234. bool createTempMaterialBakeResult;
  235. for (int i = 0; i < mBakers.Length; i++){
  236. if (mBakers[i].textureBakeResults != null){
  237. MB3_MeshBakerEditorFunctions.BakeIntoCombined(mBakers[i], out createTempMaterialBakeResult);
  238. }
  239. }
  240. } catch (Exception e) {
  241. Debug.LogError(e);
  242. }finally{
  243. EditorUtility.ClearProgressBar();
  244. }
  245. }
  246. EditorGUILayout.EndHorizontal();
  247. if (sceneAnalysisResults.Count > 0){
  248. float height = position.height - 150f;
  249. if (height < 500f) height = 500f;
  250. MB_EditorUtil.DrawSeparator();
  251. scrollPos2 = EditorGUILayout.BeginScrollView(scrollPos2,false,true); //(scrollPos2,, GUILayout.Width(position.width - 20f), GUILayout.Height(height));
  252. EditorGUILayout.LabelField("Shaders In Scene",EditorStyles.boldLabel);
  253. for(int i = 0; i < sceneAnalysisResults.Count; i++){
  254. List<GameObjectFilterInfo> gows = sceneAnalysisResults[i];
  255. EditorGUILayout.BeginHorizontal();
  256. if (GUILayout.Button ("Generate Baker",GUILayout.Width(200))){
  257. createAndSetupBaker(gows,generate_AssetsFolder);
  258. }
  259. if (GUILayout.Button("Select", GUILayout.Width(200)))
  260. {
  261. UnityEngine.Object[] selected = new UnityEngine.Object[gows.Count];
  262. for (int j = 0; j < gows.Count; j++)
  263. {
  264. selected[j] = gows[j].go;
  265. }
  266. Selection.objects = selected;
  267. SceneView.lastActiveSceneView.FrameSelected();
  268. }
  269. string descr = String.Format("Objs={0} AtlasIndex={1} {2}", gows.Count, gows[0].atlasIndex, gows[0].GetDescription(filters,gows[0]));
  270. EditorGUILayout.LabelField(descr, EditorStyles.wordWrappedLabel);
  271. EditorGUILayout.EndHorizontal();
  272. sceneAnalysisResultsFoldouts[i] = EditorGUILayout.Foldout(sceneAnalysisResultsFoldouts[i],"");
  273. if (sceneAnalysisResultsFoldouts[i]){
  274. EditorGUI.indentLevel += 1;
  275. for (int j = 0; j < gows.Count; j++){
  276. if (gows[j].go != null){
  277. EditorGUILayout.LabelField(gows[j].go.name + " " + gows[j].GetDescription(filters,gows[j]));
  278. }
  279. }
  280. EditorGUI.indentLevel -= 1;
  281. }
  282. }
  283. EditorGUILayout.EndScrollView();
  284. MB_EditorUtil.DrawSeparator();
  285. }
  286. }
  287. void drawTabAddObjectsToBakers(){
  288. if (helpBoxString == null) helpBoxString = "";
  289. 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." +
  290. "To remove, use the fields below to filter what is removed.\n" + helpBoxString, UnityEditor.MessageType.None);
  291. target = (MB3_MeshBakerRoot) EditorGUILayout.ObjectField("Target to add objects to",target,typeof(MB3_MeshBakerRoot),true);
  292. if (target != null){
  293. targetGO = target.gameObject;
  294. } else {
  295. targetGO = null;
  296. }
  297. if (targetGO != oldTargetGO && targetGO != null){
  298. textureBaker = targetGO.GetComponent<MB3_TextureBaker>();
  299. meshBaker = targetGO.GetComponent<MB3_MeshBaker>();
  300. tbe = new MB3_TextureBakerEditorInternal();
  301. mbe = new MB3_MeshBakerEditorInternal();
  302. oldTargetGO = targetGO;
  303. if (textureBaker != null)
  304. {
  305. serializedObject = new SerializedObject(textureBaker);
  306. tbe.OnEnable(serializedObject);
  307. }
  308. else if (meshBaker != null)
  309. {
  310. serializedObject = new SerializedObject(meshBaker);
  311. mbe.OnEnable(serializedObject);
  312. }
  313. }
  314. EditorGUIUtility.labelWidth = 300;
  315. onlyStaticObjects = EditorGUILayout.Toggle("Only Static Objects", onlyStaticObjects);
  316. onlyEnabledObjects = EditorGUILayout.Toggle("Only Enabled Objects", onlyEnabledObjects);
  317. excludeMeshesWithOBuvs = EditorGUILayout.Toggle("Exclude meshes with out-of-bounds UVs", excludeMeshesWithOBuvs);
  318. excludeMeshesAlreadyAddedToBakers = EditorGUILayout.Toggle("Exclude GameObjects already added to bakers", excludeMeshesAlreadyAddedToBakers);
  319. lodLevelToInclude = EditorGUILayout.IntPopup("Only include objects on LOD Level", lodLevelToInclude, LODLevelLabels, LODLevelValues);
  320. mat = (Material) EditorGUILayout.ObjectField("Using Material",mat,typeof(Material),true);
  321. shaderMat = (Material) EditorGUILayout.ObjectField("Using Shader",shaderMat,typeof(Material),true);
  322. string[] lightmapDisplayValues = new string[257];
  323. int[] lightmapValues = new int[257];
  324. lightmapValues[0] = -2;
  325. lightmapValues[1] = -1;
  326. lightmapDisplayValues[0] = "don't filter on lightmapping";
  327. lightmapDisplayValues[1] = "not lightmapped";
  328. for (int i = 2; i < lightmapDisplayValues.Length; i++){
  329. lightmapDisplayValues[i] = "" + i;
  330. lightmapValues[i] = i;
  331. }
  332. EditorGUILayout.BeginHorizontal();
  333. EditorGUILayout.LabelField("Using Lightmap Index ");
  334. lightmapIndex = EditorGUILayout.IntPopup(lightmapIndex,
  335. lightmapDisplayValues,
  336. lightmapValues);
  337. EditorGUILayout.EndHorizontal();
  338. if (regExParseError != null && regExParseError.Length > 0)
  339. {
  340. EditorGUILayout.HelpBox("Error In Regular Expression:\n" + regExParseError, MessageType.Error);
  341. }
  342. searchRegEx = EditorGUILayout.TextField(GUIContentRegExpression, searchRegEx);
  343. EditorGUILayout.Separator();
  344. EditorGUILayout.BeginHorizontal();
  345. if (GUILayout.Button("Add Selected Meshes To Target")){
  346. addSelectedObjects();
  347. }
  348. if (GUILayout.Button("Remove Matching Meshes From Target"))
  349. {
  350. removeSelectedObjects();
  351. }
  352. EditorGUILayout.EndHorizontal();
  353. if (textureBaker != null){
  354. MB_EditorUtil.DrawSeparator();
  355. tbFoldout = EditorGUILayout.Foldout(tbFoldout,"Texture Baker");
  356. if (tbFoldout){
  357. tbe.DrawGUI(serializedObject, (MB3_TextureBaker) textureBaker, typeof(MB3_MeshBakerEditorWindow));
  358. }
  359. }
  360. if (meshBaker != null){
  361. MB_EditorUtil.DrawSeparator();
  362. mbFoldout = EditorGUILayout.Foldout(mbFoldout,"Mesh Baker");
  363. if (mbFoldout){
  364. mbe.DrawGUI(serializedObject, (MB3_MeshBaker) meshBaker, typeof(MB3_MeshBakerEditorWindow));
  365. }
  366. }
  367. }
  368. List<GameObject> GetFilteredList() {
  369. List<GameObject> newMomObjs = new List<GameObject>();
  370. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
  371. if (mom == null) {
  372. Debug.LogError("Must select a target MeshBaker to add objects to");
  373. return newMomObjs;
  374. }
  375. GameObject dontAddMe = null;
  376. Renderer r = MB_Utility.GetRenderer(mom.gameObject);
  377. if (r != null) { //make sure that this MeshBaker object is not in list
  378. dontAddMe = r.gameObject;
  379. }
  380. MB3_MeshBakerRoot[] allBakers = FindObjectsOfType<MB3_MeshBakerRoot>();
  381. HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
  382. for (int i = 0; i < allBakers.Length; i++) {
  383. List<GameObject> objsToCombine = allBakers[i].GetObjectsToCombine();
  384. for (int j = 0; j < objsToCombine.Count; j++) {
  385. if (objsToCombine[j] != null) objectsAlreadyIncludedInBakers.Add(objsToCombine[j]);
  386. }
  387. }
  388. GameObject[] gos = Selection.gameObjects;
  389. if (gos.Length == 0) {
  390. Debug.LogWarning("No objects selected in hierarchy view. Nothing added. Try selecting some objects.");
  391. return newMomObjs;
  392. }
  393. List<GameObject> mrs = new List<GameObject>();
  394. for (int i = 0; i < gos.Length; i++)
  395. {
  396. GameObject go = gos[i];
  397. Renderer[] rs = go.GetComponentsInChildren<Renderer>();
  398. for (int j = 0; j < rs.Length; j++)
  399. {
  400. if (rs[j] is MeshRenderer || rs[j] is SkinnedMeshRenderer)
  401. {
  402. mrs.Add(rs[j].gameObject);
  403. }
  404. }
  405. }
  406. newMomObjs = FilterList(mrs, objectsAlreadyIncludedInBakers, dontAddMe);
  407. return newMomObjs;
  408. }
  409. int GetLODLevelForRenderer(Renderer r)
  410. {
  411. if (r != null)
  412. {
  413. LODGroup lodGroup = r.GetComponentInParent<LODGroup>();
  414. if (lodGroup != null) {
  415. LOD[] lods = lodGroup.GetLODs();
  416. for (int lodIdx = 0; lodIdx < lods.Length; lodIdx++)
  417. {
  418. Renderer[] rs = lods[lodIdx].renderers;
  419. for (int j = 0; j < rs.Length; j++)
  420. {
  421. if (rs[j] == r)
  422. {
  423. return lodIdx;
  424. }
  425. }
  426. }
  427. }
  428. }
  429. return 0;
  430. }
  431. List<GameObject> FilterList(List<GameObject> mrss, HashSet<GameObject> objectsAlreadyIncludedInBakers, GameObject dontAddMe) {
  432. int numInSelection = 0;
  433. int numStaticExcluded = 0;
  434. int numEnabledExcluded = 0;
  435. int numLightmapExcluded = 0;
  436. int numLodLevelExcluded = 0;
  437. int numOBuvExcluded = 0;
  438. int numMatExcluded = 0;
  439. int numShaderExcluded = 0;
  440. int numRegExExcluded = 0;
  441. int numAlreadyIncludedExcluded = 0;
  442. System.Text.RegularExpressions.Regex regex = null;
  443. if (searchRegEx != null && searchRegEx.Length > 0)
  444. {
  445. try
  446. {
  447. regex = new System.Text.RegularExpressions.Regex(searchRegEx);
  448. regExParseError = "";
  449. }
  450. catch (Exception ex)
  451. {
  452. regExParseError = ex.Message;
  453. }
  454. }
  455. Dictionary<int,MB_Utility.MeshAnalysisResult> meshAnalysisResultsCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>(); //cache results
  456. List<GameObject> newMomObjs = new List<GameObject>();
  457. for (int j = 0; j < mrss.Count; j++)
  458. {
  459. if (mrss[j] == null)
  460. {
  461. continue;
  462. }
  463. Renderer mrs = mrss[j].GetComponent<Renderer>();
  464. if (mrs is MeshRenderer || mrs is SkinnedMeshRenderer)
  465. {
  466. if (mrs.GetComponent<TextMesh>() != null)
  467. {
  468. continue; //don't add TextMeshes
  469. }
  470. numInSelection++;
  471. if (!newMomObjs.Contains(mrs.gameObject))
  472. {
  473. bool addMe = true;
  474. if (!mrs.gameObject.isStatic && onlyStaticObjects)
  475. {
  476. numStaticExcluded++;
  477. addMe = false;
  478. continue;
  479. }
  480. if (!mrs.enabled && onlyEnabledObjects)
  481. {
  482. numEnabledExcluded++;
  483. addMe = false;
  484. continue;
  485. }
  486. if (lightmapIndex != -2)
  487. {
  488. if (mrs.lightmapIndex != lightmapIndex)
  489. {
  490. numLightmapExcluded++;
  491. addMe = false;
  492. continue;
  493. }
  494. }
  495. if (lodLevelToInclude == -1)
  496. {
  497. // not filtering on LODLevel
  498. }
  499. else
  500. {
  501. if (GetLODLevelForRenderer(mrs) != lodLevelToInclude)
  502. {
  503. numLodLevelExcluded++;
  504. addMe = false;
  505. continue;
  506. }
  507. }
  508. if (excludeMeshesAlreadyAddedToBakers && objectsAlreadyIncludedInBakers.Contains(mrs.gameObject))
  509. {
  510. numAlreadyIncludedExcluded++;
  511. addMe = false;
  512. continue;
  513. }
  514. Mesh mm = MB_Utility.GetMesh(mrs.gameObject);
  515. if (mm != null)
  516. {
  517. MB_Utility.MeshAnalysisResult mar;
  518. if (!meshAnalysisResultsCache.TryGetValue(mm.GetInstanceID(), out mar))
  519. {
  520. MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
  521. meshAnalysisResultsCache.Add(mm.GetInstanceID(), mar);
  522. }
  523. if (mar.hasOutOfBoundsUVs && excludeMeshesWithOBuvs)
  524. {
  525. numOBuvExcluded++;
  526. addMe = false;
  527. continue;
  528. }
  529. }
  530. if (shaderMat != null)
  531. {
  532. Material[] nMats = mrs.sharedMaterials;
  533. bool usesShader = false;
  534. foreach (Material nMat in nMats)
  535. {
  536. if (nMat != null && nMat.shader == shaderMat.shader)
  537. {
  538. usesShader = true;
  539. }
  540. }
  541. if (!usesShader)
  542. {
  543. numShaderExcluded++;
  544. addMe = false;
  545. continue;
  546. }
  547. }
  548. if (mat != null)
  549. {
  550. Material[] nMats = mrs.sharedMaterials;
  551. bool usesMat = false;
  552. foreach (Material nMat in nMats)
  553. {
  554. if (nMat == mat)
  555. {
  556. usesMat = true;
  557. }
  558. }
  559. if (!usesMat)
  560. {
  561. numMatExcluded++;
  562. addMe = false;
  563. continue;
  564. }
  565. }
  566. if (regex != null)
  567. {
  568. if (!regex.IsMatch(mrs.gameObject.name))
  569. {
  570. numRegExExcluded++;
  571. addMe = false;
  572. continue;
  573. }
  574. }
  575. if (addMe && mrs.gameObject != dontAddMe)
  576. {
  577. if (!newMomObjs.Contains(mrs.gameObject))
  578. {
  579. newMomObjs.Add(mrs.gameObject);
  580. }
  581. }
  582. }
  583. }
  584. }
  585. System.Text.StringBuilder sb = new System.Text.StringBuilder();
  586. //sb.AppendFormat("Total objects in selection {0}\n", numInSelection);
  587. //Debug.Log( "Total objects in selection " + numInSelection);
  588. if (numStaticExcluded > 0)
  589. {
  590. sb.AppendFormat(" {0} objects were excluded because they were not static\n", numStaticExcluded);
  591. Debug.Log(numStaticExcluded + " objects were excluded because they were not static\n");
  592. }
  593. if (numEnabledExcluded > 0)
  594. {
  595. sb.AppendFormat(" {0} objects were excluded because they were disabled\n", numEnabledExcluded);
  596. Debug.Log(numEnabledExcluded + " objects were excluded because they were disabled\n");
  597. }
  598. if (numOBuvExcluded > 0)
  599. {
  600. sb.AppendFormat(" {0} objects were excluded because they were had out of bounds uvs\n", numOBuvExcluded);
  601. Debug.Log(numOBuvExcluded + " objects were excluded because they had out of bounds uvs\n");
  602. }
  603. if (numLightmapExcluded > 0)
  604. {
  605. sb.AppendFormat(" {0} objects were excluded because they did not match lightmap filter.\n", numLightmapExcluded);
  606. Debug.Log(numLightmapExcluded + " objects did not match lightmap filter.\n");
  607. }
  608. if (numLodLevelExcluded > 0)
  609. {
  610. sb.AppendFormat(" {0} objects were excluded because they did not match the selected LOD level filter.\n", numLodLevelExcluded);
  611. Debug.Log(numLodLevelExcluded + " objects did not match LOD level filter.\n");
  612. }
  613. if (numShaderExcluded > 0)
  614. {
  615. sb.AppendFormat(" {0} objects were excluded because they did not use the selected shader.\n", numShaderExcluded);
  616. Debug.Log(numShaderExcluded + " objects were excluded because they did not use the selected shader.\n");
  617. }
  618. if (numMatExcluded > 0)
  619. {
  620. sb.AppendFormat(" {0} objects were excluded because they did not use the selected material.\n", numMatExcluded);
  621. Debug.Log(numMatExcluded + " objects were excluded because they did not use the selected material.\n");
  622. }
  623. if (numRegExExcluded > 0)
  624. {
  625. sb.AppendFormat(" {0} objects were excluded because they did not match the regular expression.\n", numRegExExcluded);
  626. Debug.Log(numRegExExcluded + " objects were excluded because they did not match the regular expression.\n");
  627. }
  628. if (numAlreadyIncludedExcluded > 0)
  629. {
  630. sb.AppendFormat(" {0} objects were excluded because they did were already included in other bakers.\n", numAlreadyIncludedExcluded);
  631. Debug.Log(numAlreadyIncludedExcluded + " objects were excluded because they did were already included in other bakers.\n");
  632. }
  633. helpBoxString = sb.ToString();
  634. return newMomObjs;
  635. }
  636. void removeSelectedObjects()
  637. {
  638. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
  639. if (mom == null)
  640. {
  641. Debug.LogError("Must select a target MeshBaker to add objects to");
  642. return;
  643. }
  644. List<GameObject> objsToCombine = mom.GetObjectsToCombine();
  645. HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
  646. GameObject dontAddMe = null;
  647. Renderer r = MB_Utility.GetRenderer(mom.gameObject);
  648. if (r != null)
  649. { //make sure that this MeshBaker object is not in list
  650. dontAddMe = r.gameObject;
  651. }
  652. List<GameObject> objsToRemove = FilterList(objsToCombine, objectsAlreadyIncludedInBakers, dontAddMe);
  653. for (int i = 0; i < objsToRemove.Count; i++)
  654. {
  655. objsToCombine.Remove(objsToRemove[i]);
  656. }
  657. SerializedObject so = new SerializedObject(mom);
  658. so.SetIsDifferentCacheDirty();
  659. Debug.Log("Removed " + objsToRemove.Count + " objects from " + mom.name);
  660. helpBoxString += String.Format("\nRemoved {0} objects from {1}", objsToRemove.Count, mom.name);
  661. }
  662. void addSelectedObjects(){
  663. MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot) target;
  664. if (mom == null){
  665. Debug.LogError("Must select a target MeshBaker to add objects to");
  666. return;
  667. }
  668. List<GameObject> newMomObjs = GetFilteredList();
  669. MBVersionEditor.RegisterUndo(mom, "Add Objects");
  670. List<GameObject> momObjs = mom.GetObjectsToCombine();
  671. int numAdded = 0;
  672. int numAlreadyInList = 0;
  673. for (int i = 0; i < newMomObjs.Count;i++){
  674. if (!momObjs.Contains(newMomObjs[i])){
  675. momObjs.Add(newMomObjs[i]);
  676. numAdded++;
  677. } else
  678. {
  679. numAlreadyInList++;
  680. }
  681. }
  682. SerializedObject so = new SerializedObject(mom);
  683. so.SetIsDifferentCacheDirty();
  684. if (numAlreadyInList > 0)
  685. {
  686. Debug.Log(String.Format("Skipped adding {0} objects to Target because these objects had already been added to this Target. ", numAlreadyInList));
  687. }
  688. if (numAdded == 0){
  689. 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");
  690. } else {
  691. Debug.Log(string.Format("Added {0} objects to {1}. ", numAdded, mom.name));
  692. }
  693. helpBoxString += String.Format("\nAdded {0} objects to {1}", numAdded, mom.name);
  694. }
  695. void listMaterialsInScene(){
  696. if (!ValidateGroupByFields()) return;
  697. if (groupByOptionFilters == null)
  698. {
  699. populateGroupByFilters();
  700. }
  701. List<IGroupByFilter> gbfs = new List<IGroupByFilter>();
  702. for (int i = 0; i < groupByFilterIdxs.Length; i++)
  703. {
  704. if (groupByFilterIdxs[i] != 0)
  705. {
  706. gbfs.Add(groupByOptionFilters[groupByFilterIdxs[i]]);
  707. }
  708. }
  709. filters = gbfs.ToArray();
  710. //Get All Objects Already In a list of objects to be combined
  711. MB3_MeshBakerRoot[] allBakers = FindObjectsOfType<MB3_MeshBakerRoot>();
  712. HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
  713. for (int i = 0; i < allBakers.Length; i++){
  714. List<GameObject> objsToCombine = allBakers[i].GetObjectsToCombine();
  715. for (int j = 0; j < objsToCombine.Count; j++){
  716. if (objsToCombine[j] != null) objectsAlreadyIncludedInBakers.Add(objsToCombine[j]);
  717. }
  718. }
  719. //collect all renderers in scene
  720. List<GameObjectFilterInfo> gameObjects = new List<GameObjectFilterInfo>();
  721. Renderer[] rs = (Renderer[]) FindObjectsOfType(typeof(Renderer));
  722. // Profile.StartProfile("listMaterialsInScene1");
  723. EditorUtility.DisplayProgressBar("Analysing Scene","Collecting Renderers",.25f);
  724. for (int i = 0; i < rs.Length; i++){
  725. Renderer r = rs[i];
  726. if (r is MeshRenderer || r is SkinnedMeshRenderer){
  727. if (r.GetComponent<TextMesh>() != null){
  728. continue; //don't add TextMeshes
  729. }
  730. GameObjectFilterInfo goaw = new GameObjectFilterInfo(r.gameObject,objectsAlreadyIncludedInBakers, filters);
  731. if (goaw.materials.Length > 0) //don't consider renderers with no materials
  732. {
  733. gameObjects.Add(goaw);
  734. EditorUtility.DisplayProgressBar("Analysing Scene", "Collecting Renderer For " + r.name, .1f);
  735. }
  736. }
  737. }
  738. //analyse meshes
  739. Dictionary<int,MB_Utility.MeshAnalysisResult> meshAnalysisResultCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>();
  740. int totalVerts = 0;
  741. for (int i = 0; i < gameObjects.Count; i++){
  742. string rpt = String.Format ("Processing {0} [{1} of {2}]",gameObjects[i].go.name,i,gameObjects.Count);
  743. EditorUtility.DisplayProgressBar("Analysing Scene",rpt + " A",.6f);
  744. Mesh mm = MB_Utility.GetMesh(gameObjects[i].go);
  745. int nVerts = 0;
  746. if (mm != null){
  747. nVerts += mm.vertexCount;
  748. MB_Utility.MeshAnalysisResult mar;
  749. if (!meshAnalysisResultCache.TryGetValue(mm.GetInstanceID(),out mar)){
  750. EditorUtility.DisplayProgressBar("Analysing Scene",rpt + " Check Out Of Bounds UVs",.6f);
  751. MB_Utility.hasOutOfBoundsUVs(mm,ref mar);
  752. //Rect dummy = mar.uvRect;
  753. MB_Utility.doSubmeshesShareVertsOrTris(mm,ref mar);
  754. meshAnalysisResultCache.Add (mm.GetInstanceID(),mar);
  755. }
  756. if (mar.hasOutOfBoundsUVs){
  757. int w = (int) mar.uvRect.width;
  758. int h = (int) mar.uvRect.height;
  759. gameObjects[i].outOfBoundsUVs = true;
  760. gameObjects[i].warning += " [WARNING: has uvs outside the range (0,1) tex is tiled " + w + "x" + h + " times]";
  761. }
  762. if (mar.hasOverlappingSubmeshVerts){
  763. gameObjects[i].submeshesOverlap = true;
  764. gameObjects[i].warning += " [WARNING: Submeshes share verts or triangles. 'Multiple Combined Materials' feature may not work.]";
  765. }
  766. }
  767. totalVerts += nVerts;
  768. EditorUtility.DisplayProgressBar("Analysing Scene",rpt + " Validate OBuvs Multi Material",.6f);
  769. Renderer mr = gameObjects[i].go.GetComponent<Renderer>();
  770. if (!MB_Utility.AreAllSharedMaterialsDistinct(mr.sharedMaterials)){
  771. gameObjects[i].warning += " [WARNING: Object uses same material on multiple submeshes. This may produce poor results when used with multiple materials or fix out of bounds uvs.]";
  772. }
  773. }
  774. List<GameObjectFilterInfo> objsNotAddedToBaker = new List<GameObjectFilterInfo>();
  775. Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap = sortIntoBakeGroups3(gameObjects, objsNotAddedToBaker, filters, splitAtlasesSoMeshesFit, atlasSize);
  776. sceneAnalysisResults = new List<List<GameObjectFilterInfo>>();
  777. foreach (GameObjectFilterInfo gow in gs2bakeGroupMap.Keys){
  778. List<List<GameObjectFilterInfo>> gows = gs2bakeGroupMap[gow];
  779. for (int i = 0; i < gows.Count; i++) //if split atlases by what fits in atlas
  780. {
  781. sceneAnalysisResults.Add(gows[i]);
  782. }
  783. }
  784. sceneAnalysisResultsFoldouts = new bool[sceneAnalysisResults.Count];
  785. for (int i = 0; i < sceneAnalysisResults.Count; i++) { sceneAnalysisResultsFoldouts[i] = true; }
  786. if (writeReportFile)
  787. {
  788. string fileName = Application.dataPath + "/MeshBakerSceneAnalysisReport.txt";
  789. try
  790. {
  791. System.IO.File.WriteAllText(fileName, generateSceneAnalysisReport(gs2bakeGroupMap, objsNotAddedToBaker));
  792. Debug.Log(String.Format("Wrote scene analysis file to '{0}'. This file contains a list of all renderers and the materials/shaders that they use. It is designed to be opened with a spreadsheet.", fileName));
  793. }
  794. catch (Exception e)
  795. {
  796. e.GetHashCode(); //supress compiler warning
  797. Debug.Log("Failed to write file: " + fileName);
  798. }
  799. }
  800. }
  801. string generateSceneAnalysisReport(Dictionary<GameObjectFilterInfo,List<List<GameObjectFilterInfo>>> gs2bakeGroupMap, List<GameObjectFilterInfo> objsNotAddedToBaker){
  802. string outStr = "(Click me, if I am too big copy and paste me into a spreadsheet or text editor)\n";// Materials in scene " + shader2GameObjects.Keys.Count + " and the objects that use them:\n";
  803. outStr += "\t\tOBJECT NAME\tLIGHTMAP INDEX\tSTATIC\tOVERLAPPING SUBMESHES\tOUT-OF-BOUNDS UVs\tNUM MATS\tMATERIAL\tWARNINGS\n";
  804. int totalVerts = 0;
  805. string outStr2 = "";
  806. foreach(List<List<GameObjectFilterInfo>> goss in gs2bakeGroupMap.Values){
  807. for (int atlasIdx = 0; atlasIdx < goss.Count; atlasIdx++)
  808. {
  809. List<GameObjectFilterInfo> gos = goss[atlasIdx];
  810. outStr2 = "";
  811. totalVerts = 0;
  812. gos.Sort();
  813. for (int i = 0; i < gos.Count; i++)
  814. {
  815. totalVerts += gos[i].numVerts;
  816. string matStr = "";
  817. Renderer mr = gos[i].go.GetComponent<Renderer>();
  818. foreach (Material mmm in mr.sharedMaterials)
  819. {
  820. matStr += "[" + mmm + "] ";
  821. }
  822. outStr2 += "\t\t" + gos[i].go.name + " (" + gos[i].numVerts + " verts)\t" + gos[i].lightmapIndex + "\t" + gos[i].isStatic + "\t" + gos[i].submeshesOverlap + "\t" + gos[i].outOfBoundsUVs + "\t" + gos[i].numMaterials + "\t" + matStr + "\t" + gos[i].warning + "\n";
  823. }
  824. outStr2 = "\t" + gos[0].shaderName + " (" + totalVerts + " verts): \n" + outStr2;
  825. outStr += outStr2;
  826. }
  827. }
  828. if (objsNotAddedToBaker.Count > 0){
  829. outStr += "Other objects\n";
  830. string shaderName = "";
  831. totalVerts = 0;
  832. List<GameObjectFilterInfo> gos1 = objsNotAddedToBaker;
  833. gos1.Sort();
  834. outStr2 = "";
  835. for (int i = 0; i < gos1.Count; i++){
  836. if (!shaderName.Equals( objsNotAddedToBaker[i].shaderName )){
  837. outStr2 += "\t" + gos1[0].shaderName + "\n";
  838. shaderName = objsNotAddedToBaker[i].shaderName;
  839. }
  840. totalVerts += gos1[i].numVerts;
  841. string matStr = "";
  842. Renderer mr = gos1[i].go.GetComponent<Renderer>();
  843. foreach(Material mmm in mr.sharedMaterials){
  844. matStr += "[" + mmm + "] ";
  845. }
  846. outStr2 += "\t\t" + gos1[i].go.name + " (" + gos1[i].numVerts + " verts)\t" + gos1[i].lightmapIndex + "\t" + gos1[i].isStatic + "\t" + gos1[i].submeshesOverlap + "\t" + gos1[i].outOfBoundsUVs + "\t" + gos1[i].numMaterials + "\t" + matStr + "\t" + gos1[i].warning + "\n";
  847. }
  848. outStr += outStr2;
  849. }
  850. return outStr;
  851. }
  852. bool MaterialsAreTheSame(GameObjectFilterInfo a, GameObjectFilterInfo b){
  853. HashSet<Material> aMats = new HashSet<Material>();
  854. for(int i = 0; i < a.materials.Length; i++) aMats.Add(a.materials[i]);
  855. HashSet<Material> bMats = new HashSet<Material>();
  856. for(int i = 0; i < b.materials.Length; i++) bMats.Add(b.materials[i]);
  857. return aMats.SetEquals(bMats);
  858. }
  859. bool ShadersAreTheSame(GameObjectFilterInfo a, GameObjectFilterInfo b){
  860. HashSet<Shader> aMats = new HashSet<Shader>();
  861. for(int i = 0; i < a.shaders.Length; i++) aMats.Add(a.shaders[i]);
  862. HashSet<Shader> bMats = new HashSet<Shader>();
  863. for(int i = 0; i < b.shaders.Length; i++) bMats.Add(b.shaders[i]);
  864. return aMats.SetEquals(bMats);
  865. }
  866. public static Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> sortIntoBakeGroups3(List<GameObjectFilterInfo> gameObjects, List<GameObjectFilterInfo> objsNotAddedToBaker, IGroupByFilter[] filters, bool splitAtlasesSoMeshesFit, int atlasSize)
  867. {
  868. Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap = new Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>>();
  869. List<GameObjectFilterInfo> gos = gameObjects;
  870. if (gos.Count < 1) return gs2bakeGroupMap;
  871. gos.Sort();
  872. List<List<GameObjectFilterInfo>> l = null;
  873. GameObjectFilterInfo key = gos[0];
  874. for (int i = 0; i < gos.Count; i++){
  875. GameObjectFilterInfo goaw = gos[i];
  876. //compare with key and decide if we need a new list
  877. for (int j = 0; j < filters.Length; j++){
  878. if (filters[j] != null && filters[j].Compare(key,goaw) != 0) l = null;
  879. }
  880. if (l == null){
  881. l = new List<List<GameObjectFilterInfo>>();
  882. l.Add(new List<GameObjectFilterInfo>());
  883. gs2bakeGroupMap.Add(gos[i],l);
  884. key = gos[i];
  885. }
  886. l[0].Add(gos[i]);
  887. }
  888. //now that objects have been grouped by the sort criteria we can see how many atlases are needed
  889. Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap2 = new Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>>();
  890. if (splitAtlasesSoMeshesFit)
  891. {
  892. foreach (GameObjectFilterInfo k in gs2bakeGroupMap.Keys)
  893. {
  894. List<GameObjectFilterInfo> vs = gs2bakeGroupMap[k][0];
  895. List<GameObject> objsInGroup = new List<GameObject>();
  896. for (int i = 0; i < vs.Count; i++)
  897. {
  898. objsInGroup.Add(vs[i].go);
  899. }
  900. MB3_TextureCombiner tc = new MB3_TextureCombiner();
  901. tc.maxAtlasSize = atlasSize;
  902. tc.LOG_LEVEL = MB2_LogLevel.warn;
  903. List<AtlasPackingResult> packingResults = new List<AtlasPackingResult>();
  904. Material tempResMat = k.materials[0]; //we don't write to the materials so can use this as the result material
  905. if (tc.CombineTexturesIntoAtlases(null, null, tempResMat, objsInGroup, null, null, packingResults, true))
  906. {
  907. List<List<GameObjectFilterInfo>> atlasGroups = new List<List<GameObjectFilterInfo>>();
  908. for (int i = 0; i < packingResults.Count; i++)
  909. {
  910. List<GameObjectFilterInfo> ngos = new List<GameObjectFilterInfo>();
  911. List<MatsAndGOs> matsData = (List<MatsAndGOs>)packingResults[i].data;
  912. for (int j = 0; j < matsData.Count; j++)
  913. {
  914. for (int kk = 0; kk < matsData[j].gos.Count; kk++)
  915. {
  916. GameObjectFilterInfo gofi = vs.Find(x => x.go == matsData[j].gos[kk]);
  917. //Debug.Assert(gofi != null);
  918. ngos.Add(gofi);
  919. }
  920. }
  921. ngos[0].atlasIndex = (short) i;
  922. atlasGroups.Add(ngos);
  923. }
  924. gs2bakeGroupMap2.Add(k, atlasGroups);
  925. } else
  926. {
  927. gs2bakeGroupMap2.Add(k, gs2bakeGroupMap[k]);
  928. }
  929. }
  930. } else
  931. {
  932. gs2bakeGroupMap2 = gs2bakeGroupMap;
  933. }
  934. return gs2bakeGroupMap2;
  935. }
  936. void createBakers(Dictionary<GameObjectFilterInfo,List<GameObjectFilterInfo>> gs2bakeGroupMap, List<GameObjectFilterInfo> objsNotAddedToBaker){
  937. string s = "";
  938. int numBakers = 0;
  939. int numObjsAdded = 0;
  940. if (generate_AssetsFolder == null || generate_AssetsFolder == ""){
  941. Debug.LogError("Need to choose a folder for saving the combined material assets.");
  942. return;
  943. }
  944. List<GameObjectFilterInfo> singletonObjsNotAddedToBaker = new List<GameObjectFilterInfo>();
  945. foreach(List<GameObjectFilterInfo> gaw in gs2bakeGroupMap.Values){
  946. if (gaw.Count > 1){
  947. numBakers ++;
  948. numObjsAdded += gaw.Count;
  949. createAndSetupBaker(gaw, generate_AssetsFolder);
  950. s += " Created meshbaker for shader=" + gaw[0].shaderName + " lightmap=" + gaw[0].lightmapIndex + " OBuvs=" + gaw[0].outOfBoundsUVs + "\n";
  951. } else {
  952. singletonObjsNotAddedToBaker.Add(gaw[0]);
  953. }
  954. }
  955. s = "Created " + numBakers + " bakers. Added " + numObjsAdded + " objects\n" + s;
  956. Debug.Log(s);
  957. s = "Objects not added=" + objsNotAddedToBaker.Count + " objects that have unique material=" + singletonObjsNotAddedToBaker.Count + "\n";
  958. for (int i = 0; i < objsNotAddedToBaker.Count; i++){
  959. s += " " + objsNotAddedToBaker[i].go.name +
  960. " isStatic=" + objsNotAddedToBaker[i].isStatic +
  961. " submeshesOverlap" + objsNotAddedToBaker[i].submeshesOverlap +
  962. " numMats=" + objsNotAddedToBaker[i].numMaterials + "\n";
  963. }
  964. for (int i = 0; i < singletonObjsNotAddedToBaker.Count; i++){
  965. s += " " + singletonObjsNotAddedToBaker[i].go.name + " single\n";
  966. }
  967. Debug.Log(s);
  968. }
  969. void createAndSetupBaker(List<GameObjectFilterInfo> gaws, string pthRoot){
  970. for (int i = gaws.Count - 1; i >= 0; i--){
  971. if (gaws[i].go == null) gaws.RemoveAt(i);
  972. }
  973. if (gaws.Count < 1){
  974. Debug.LogError ("No game objects.");
  975. return;
  976. }
  977. if (pthRoot == null || pthRoot == ""){
  978. Debug.LogError ("Folder for saving created assets was not set.");
  979. return;
  980. }
  981. int numVerts = 0;
  982. for (int i = 0; i < gaws.Count; i++){
  983. if (gaws[i].go != null){
  984. numVerts = gaws[i].numVerts;
  985. }
  986. }
  987. GameObject newMeshBaker = null;
  988. if (numVerts >= 65535){
  989. newMeshBaker = MB3_MultiMeshBakerEditor.CreateNewMeshBaker();
  990. } else {
  991. newMeshBaker = MB3_MeshBakerEditor.CreateNewMeshBaker();
  992. }
  993. newMeshBaker.name = ("MeshBaker-" + gaws[0].shaderName + "-LM" + gaws[0].lightmapIndex).ToString().Replace("/","-");
  994. MB3_TextureBaker tb = newMeshBaker.GetComponent<MB3_TextureBaker>();
  995. MB3_MeshBakerCommon mb = tb.GetComponentInChildren<MB3_MeshBakerCommon>();
  996. tb.GetObjectsToCombine().Clear();
  997. for (int i = 0; i < gaws.Count; i++){
  998. if (gaws[i].go != null && !tb.GetObjectsToCombine().Contains(gaws[i].go))
  999. {
  1000. tb.GetObjectsToCombine().Add(gaws[i].go);
  1001. }
  1002. }
  1003. if (splitAtlasesSoMeshesFit)
  1004. {
  1005. tb.maxAtlasSize = atlasSize;
  1006. }
  1007. if (gaws[0].numMaterials > 1){
  1008. string pthMat = AssetDatabase.GenerateUniqueAssetPath(pthRoot + newMeshBaker.name + ".asset");
  1009. MB3_TextureBakerEditorInternal.CreateCombinedMaterialAssets(tb, pthMat);
  1010. tb.doMultiMaterial = true;
  1011. SerializedObject tbr = new SerializedObject(tb);
  1012. SerializedProperty resultMaterials = tbr.FindProperty("resultMaterials");
  1013. MB3_TextureBakerEditorInternal.ConfigureMutiMaterialsFromObjsToCombine2 (tb,resultMaterials,tbr);
  1014. } else {
  1015. string pthMat = AssetDatabase.GenerateUniqueAssetPath( pthRoot + newMeshBaker.name + ".asset" );
  1016. MB3_TextureBakerEditorInternal.CreateCombinedMaterialAssets(tb, pthMat);
  1017. }
  1018. if (gaws[0].isMeshRenderer) {
  1019. mb.meshCombiner.renderType = MB_RenderType.meshRenderer;
  1020. } else {
  1021. mb.meshCombiner.renderType = MB_RenderType.skinnedMeshRenderer;
  1022. }
  1023. }
  1024. void bakeAllBakersInScene(){
  1025. MB3_MeshBakerRoot[] bakers =(MB3_MeshBakerRoot[]) FindObjectsOfType(typeof(MB3_MeshBakerRoot));
  1026. for (int i = 0; i < bakers.Length; i++){
  1027. if (bakers[i] is MB3_TextureBaker){
  1028. MB3_TextureBaker tb = (MB3_TextureBaker) bakers[i];
  1029. tb.CreateAtlases(updateProgressBar, true, new MB3_EditorMethods());
  1030. }
  1031. }
  1032. EditorUtility.ClearProgressBar();
  1033. }
  1034. /*
  1035. public void BuildAllSource(MB3_TextureBaker mom) {
  1036. SerializedObject tbr = new SerializedObject(mom);
  1037. SerializedProperty resultMaterials = tbr.FindProperty("resultMaterials");
  1038. MB3_TextureBakerEditorInternal.ConfigureMutiMaterialsFromObjsToCombine (mom,resultMaterials,tbr);
  1039. tbr.UpdateIfDirtyOrScript();
  1040. }
  1041. */
  1042. public void updateProgressBar(string msg, float progress){
  1043. EditorUtility.DisplayProgressBar("Combining Meshes", msg, progress);
  1044. }
  1045. bool ValidateGroupByFields(){
  1046. bool foundNone = false;
  1047. for (int i = 0; i < groupByFilterIdxs.Length; i++){
  1048. if (groupByFilterIdxs[i] == 0) foundNone = true; //zero is the none selection
  1049. if (foundNone && groupByFilterIdxs[i] != 0){
  1050. Debug.LogError("All non-none values must be at the top of the group by list");
  1051. return false;
  1052. }
  1053. }
  1054. for (int i = 0; i < groupByFilterIdxs.Length; i++){
  1055. for (int j = i+1; j < groupByFilterIdxs.Length; j++){
  1056. if (groupByFilterIdxs[i] == groupByFilterIdxs[j] && groupByFilterIdxs[i] != 0){
  1057. Debug.LogError("Two of the group by options are the same.");
  1058. return false;
  1059. }
  1060. }
  1061. }
  1062. return true;
  1063. }
  1064. }