MB3_MeshBakerEditorInternal.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //----------------------------------------------
  2. // MeshBaker
  3. // Copyright © 2011-2012 Ian Deane
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using System.Collections;
  7. using System.IO;
  8. using System;
  9. using System.Collections.Specialized;
  10. using System.Collections.Generic;
  11. using DigitalOpus.MB.Core;
  12. using UnityEditor;
  13. namespace DigitalOpus.MB.Core{
  14. public interface MB3_MeshBakerEditorWindowInterface{
  15. MonoBehaviour target{
  16. get;
  17. set;
  18. }
  19. }
  20. public class MB3_MeshBakerEditorInternal{
  21. //add option to exclude skinned mesh renderer and mesh renderer in filter
  22. //example scenes for multi material
  23. private static GUIContent
  24. gc_outputOptoinsGUIContent = new GUIContent("Output"),
  25. gc_logLevelContent = new GUIContent("Log Level"),
  26. gc_openToolsWindowLabelContent = new GUIContent("Open Tools For Adding Objects", "Use these tools to find out what can be combined, discover problems with meshes, and quickly add objects."),
  27. gc_renderTypeGUIContent = new GUIContent("Renderer","The type of renderer to add to the combined mesh."),
  28. gc_objectsToCombineGUIContent = new GUIContent("Custom List Of Objects To Be Combined","You can add objects here that were not on the list in the MB3_TextureBaker as long as they use a material that is in the Texture Bake Results"),
  29. gc_textureBakeResultsGUIContent = new GUIContent("Texture Bake Result","When materials are combined a MB2_TextureBakeResult Asset is generated. Drag that Asset to this field to use the combined material."),
  30. gc_useTextureBakerObjsGUIContent = new GUIContent("Same As Texture Baker","Build a combined mesh using using the same list of objects that generated the Combined Material"),
  31. gc_lightmappingOptionGUIContent = new GUIContent("Lightmapping UVs","preserve current lightmapping: Use this if all source objects are lightmapped and you want to preserve it. All source objects must use the same lightmap. DOES NOT WORK IN UNITY 5.\n\n"+
  32. "generate new UV Layout: Use this if you want to bake a lightmap after the combined mesh has been generated\n\n" +
  33. "copy UV2 unchanged: Use this if UV2 is being used for something other than lightmaping.\n\n" +
  34. "ignore UV2: A UV2 channel will not be generated for the combined mesh\n\n" +
  35. "copy UV2 unchanged to separate rects: Use this if your meshes include a custom lightmap that you want to use with the combined mesh.\n\n"),
  36. gc_combinedMeshPrefabGUIContent = new GUIContent("Combined Mesh Prefab","Create a new prefab asset an drag an empty game object to it. Drag the prefab asset to here."),
  37. gc_clearBuffersAfterBakeGUIContent = new GUIContent("Clear Buffers After Bake","Frees memory used by the MeshCombiner. Set to false if you want to update the combined mesh at runtime."),
  38. gc_doNormGUIContent = new GUIContent("Include Normals"),
  39. gc_doTanGUIContent = new GUIContent("Include Tangents"),
  40. gc_doColGUIContent = new GUIContent("Include Colors"),
  41. gc_doBlendShapeGUIContent = new GUIContent("Include Blend Shapes"),
  42. gc_doUVGUIContent = new GUIContent("Include UV"),
  43. gc_doUV3GUIContent = new GUIContent("Include UV3"),
  44. gc_doUV4GUIContent = new GUIContent("Include UV4"),
  45. gc_uv2HardAngleGUIContent = new GUIContent(" UV2 Hard Angle","Angles greater than 'hard angle' in degrees will be split."),
  46. gc_uv2PackingMarginUV3GUIContent = new GUIContent(" UV2 Packing Margin","The margin between islands in the UV layout measured in UV coordinates (0..1) not pixels"),
  47. gc_SortAlongAxis = new GUIContent("SortAlongAxis", "Transparent materials often require that triangles be rendered in a certain order. This will sort Game Objects along the specified axis. Triangles will be added to the combined mesh in this order."),
  48. gc_CenterMeshToBoundsCenter = new GUIContent("Center Mesh To Render Bounds", "Centers the verticies of the mesh about the render bounds center and translates the game object. This makes the combined meshes easier to work with. There is a performance and memory allocation cost to this so if you are frequently baking meshes at runtime disable it."),
  49. gc_OptimizeAfterBake = new GUIContent("Optimize After Bake", "This does the same thing that 'Optimize' does on the ModelImporter.");
  50. private SerializedObject meshBaker;
  51. private SerializedProperty logLevel, lightmappingOption, combiner, outputOptions, textureBakeResults, useObjsToMeshFromTexBaker, renderType, fixOutOfBoundsUVs, objsToMesh, mesh;
  52. private SerializedProperty doNorm, doTan, doUV, doUV3, doUV4, doCol, doBlendShapes, clearBuffersAfterBake, uv2OutputParamsPackingMargin, uv2OutputParamsHardAngle, sortOrderAxis, centerMeshToBoundsCenter, optimizeAfterBake;
  53. bool showInstructions = false;
  54. bool showContainsReport = true;
  55. GUIStyle editorBoxBackgroundStyle = new GUIStyle();
  56. Texture2D editorBoxBackgroundColor;
  57. Color buttonColor = new Color(.8f, .8f, 1f, 1f);
  58. void _init (SerializedObject mb) {
  59. this.meshBaker = mb;
  60. objsToMesh = meshBaker.FindProperty("objsToMesh");
  61. combiner = meshBaker.FindProperty("_meshCombiner");
  62. logLevel = combiner.FindPropertyRelative("_LOG_LEVEL");
  63. outputOptions = combiner.FindPropertyRelative("_outputOption");
  64. renderType = combiner.FindPropertyRelative("_renderType");
  65. useObjsToMeshFromTexBaker = meshBaker.FindProperty("useObjsToMeshFromTexBaker");
  66. textureBakeResults = combiner.FindPropertyRelative("_textureBakeResults");
  67. lightmappingOption = combiner.FindPropertyRelative("_lightmapOption");
  68. doNorm = combiner.FindPropertyRelative("_doNorm");
  69. doTan = combiner.FindPropertyRelative("_doTan");
  70. doUV = combiner.FindPropertyRelative("_doUV");
  71. doUV3 = combiner.FindPropertyRelative("_doUV3");
  72. doUV4 = combiner.FindPropertyRelative("_doUV4");
  73. doCol = combiner.FindPropertyRelative("_doCol");
  74. doBlendShapes = combiner.FindPropertyRelative("_doBlendShapes");
  75. uv2OutputParamsPackingMargin = combiner.FindPropertyRelative ("uv2UnwrappingParamsPackMargin");
  76. uv2OutputParamsHardAngle = combiner.FindPropertyRelative ("uv2UnwrappingParamsHardAngle");
  77. clearBuffersAfterBake = meshBaker.FindProperty("clearBuffersAfterBake");
  78. mesh = combiner.FindPropertyRelative("_mesh");
  79. sortOrderAxis = meshBaker.FindProperty("sortAxis");
  80. centerMeshToBoundsCenter = combiner.FindPropertyRelative("_recenterVertsToBoundsCenter");
  81. optimizeAfterBake = combiner.FindPropertyRelative("_optimizeAfterBake");
  82. }
  83. public void OnEnable(SerializedObject meshBaker)
  84. {
  85. _init(meshBaker);
  86. bool isPro = EditorGUIUtility.isProSkin;
  87. Color32 backgroundColor = isPro
  88. ? new Color32(35, 35, 35, 255)
  89. : new Color32(174, 174, 174, 255);
  90. editorBoxBackgroundColor = MB3_MeshBakerEditorFunctions.MakeTex(8, 8, backgroundColor);
  91. editorBoxBackgroundStyle.normal.background = editorBoxBackgroundColor;
  92. editorBoxBackgroundStyle.border = new RectOffset(0, 0, 0, 0);
  93. editorBoxBackgroundStyle.margin = new RectOffset(5, 5, 5, 5);
  94. editorBoxBackgroundStyle.padding = new RectOffset(10, 10, 10, 10);
  95. }
  96. public void OnDisable()
  97. {
  98. if (editorBoxBackgroundColor != null) GameObject.DestroyImmediate(editorBoxBackgroundColor);
  99. }
  100. public void OnInspectorGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, System.Type editorWindowType){
  101. DrawGUI(meshBaker, target, editorWindowType);
  102. }
  103. public void DrawGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, System.Type editorWindowType){
  104. if (meshBaker == null)
  105. {
  106. return;
  107. }
  108. meshBaker.Update();
  109. showInstructions = EditorGUILayout.Foldout(showInstructions,"Instructions:");
  110. if (showInstructions){
  111. EditorGUILayout.HelpBox("1. Bake combined material(s).\n\n" +
  112. "2. If necessary set the 'Texture Bake Results' field.\n\n" +
  113. "3. Add scene objects or prefabs to combine or check 'Same As Texture Baker'. For best results these should use the same shader as result material.\n\n" +
  114. "4. Select options and 'Bake'.\n\n" +
  115. "6. Look at warnings/errors in console. Decide if action needs to be taken.\n\n" +
  116. "7. (optional) Disable renderers in source objects.", UnityEditor.MessageType.None);
  117. EditorGUILayout.Separator();
  118. }
  119. MB3_MeshBakerCommon momm = (MB3_MeshBakerCommon) target;
  120. //mom.meshCombiner.LOG_LEVEL = (MB2_LogLevel) EditorGUILayout.EnumPopup("Log Level", mom.meshCombiner.LOG_LEVEL);
  121. EditorGUILayout.PropertyField(logLevel, gc_logLevelContent);
  122. EditorGUILayout.PropertyField(textureBakeResults, gc_textureBakeResultsGUIContent);
  123. if (textureBakeResults.objectReferenceValue != null){
  124. showContainsReport = EditorGUILayout.Foldout(showContainsReport, "Shaders & Materials Contained");
  125. if (showContainsReport){
  126. EditorGUILayout.HelpBox(((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).GetDescription(), MessageType.Info);
  127. }
  128. }
  129. EditorGUILayout.BeginVertical(editorBoxBackgroundStyle);
  130. EditorGUILayout.LabelField("Objects To Be Combined",EditorStyles.boldLabel);
  131. if (momm.GetTextureBaker() != null){
  132. EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
  133. } else {
  134. useObjsToMeshFromTexBaker.boolValue = false;
  135. momm.useObjsToMeshFromTexBaker = false;
  136. GUI.enabled = false;
  137. EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
  138. GUI.enabled = true;
  139. }
  140. if (!momm.useObjsToMeshFromTexBaker){
  141. if (GUILayout.Button(gc_openToolsWindowLabelContent)){
  142. MB3_MeshBakerEditorWindowInterface mmWin = (MB3_MeshBakerEditorWindowInterface) EditorWindow.GetWindow(editorWindowType);
  143. mmWin.target = (MB3_MeshBakerRoot) target;
  144. }
  145. EditorGUILayout.PropertyField(objsToMesh,gc_objectsToCombineGUIContent, true);
  146. EditorGUILayout.Separator();
  147. EditorGUILayout.BeginHorizontal();
  148. if (GUILayout.Button("Select Objects In Scene"))
  149. {
  150. Selection.objects = momm.GetObjectsToCombine().ToArray();
  151. if (momm.GetObjectsToCombine().Count > 0)
  152. {
  153. SceneView.lastActiveSceneView.pivot = momm.GetObjectsToCombine()[0].transform.position;
  154. }
  155. }
  156. if (GUILayout.Button(gc_SortAlongAxis))
  157. {
  158. MB3_MeshBakerRoot.ZSortObjects sorter = new MB3_MeshBakerRoot.ZSortObjects();
  159. sorter.sortAxis = sortOrderAxis.vector3Value;
  160. sorter.SortByDistanceAlongAxis(momm.GetObjectsToCombine());
  161. }
  162. EditorGUILayout.PropertyField(sortOrderAxis, GUIContent.none);
  163. EditorGUILayout.EndHorizontal();
  164. } else {
  165. GUI.enabled = false;
  166. EditorGUILayout.PropertyField(objsToMesh,gc_objectsToCombineGUIContent, true);
  167. GUI.enabled = true;
  168. }
  169. EditorGUILayout.EndVertical();
  170. EditorGUILayout.LabelField("Output",EditorStyles.boldLabel);
  171. if (momm is MB3_MultiMeshBaker){
  172. MB3_MultiMeshCombiner mmc = (MB3_MultiMeshCombiner) momm.meshCombiner;
  173. mmc.maxVertsInMesh = EditorGUILayout.IntField("Max Verts In Mesh", mmc.maxVertsInMesh);
  174. }
  175. EditorGUILayout.BeginHorizontal();
  176. EditorGUILayout.PropertyField(doNorm,gc_doNormGUIContent);
  177. EditorGUILayout.PropertyField(doTan,gc_doTanGUIContent);
  178. EditorGUILayout.EndHorizontal();
  179. EditorGUILayout.BeginHorizontal();
  180. EditorGUILayout.PropertyField(doUV,gc_doUVGUIContent);
  181. EditorGUILayout.PropertyField(doUV3,gc_doUV3GUIContent);
  182. EditorGUILayout.EndHorizontal();
  183. EditorGUILayout.BeginHorizontal();
  184. EditorGUILayout.PropertyField(doUV4, gc_doUV4GUIContent);
  185. EditorGUILayout.PropertyField(doCol,gc_doColGUIContent);
  186. EditorGUILayout.EndHorizontal();
  187. EditorGUILayout.PropertyField(doBlendShapes, gc_doBlendShapeGUIContent);
  188. if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.preserve_current_lightmapping) {
  189. if (MBVersion.GetMajorVersion() == 5) {
  190. EditorGUILayout.HelpBox("The best choice for Unity 5 is to Ignore_UV2 or Generate_New_UV2 layout. Unity's baked GI will create the UV2 layout it wants. See manual for more information.", MessageType.Warning);
  191. }
  192. }
  193. if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout){
  194. EditorGUILayout.HelpBox("Generating new lightmap UVs can split vertices which can push the number of vertices over the 64k limit.",MessageType.Warning);
  195. }
  196. EditorGUILayout.PropertyField(lightmappingOption,gc_lightmappingOptionGUIContent);
  197. if (momm.meshCombiner.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout){
  198. EditorGUILayout.PropertyField(uv2OutputParamsHardAngle, gc_uv2HardAngleGUIContent);
  199. EditorGUILayout.PropertyField(uv2OutputParamsPackingMargin, gc_uv2PackingMarginUV3GUIContent);
  200. EditorGUILayout.Separator();
  201. }
  202. EditorGUILayout.PropertyField(outputOptions,gc_outputOptoinsGUIContent);
  203. EditorGUILayout.PropertyField(renderType, gc_renderTypeGUIContent);
  204. if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject){
  205. //todo switch to renderer
  206. momm.meshCombiner.resultSceneObject = (GameObject) EditorGUILayout.ObjectField("Combined Mesh Object", momm.meshCombiner.resultSceneObject, typeof(GameObject), true);
  207. if (momm is MB3_MeshBaker){
  208. string l = "Mesh";
  209. if (mesh.objectReferenceValue != null) l += " ("+ mesh.objectReferenceValue.GetInstanceID() +")";
  210. EditorGUILayout.PropertyField(mesh,new GUIContent(l));
  211. }
  212. } else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab){
  213. momm.resultPrefab = (GameObject) EditorGUILayout.ObjectField(gc_combinedMeshPrefabGUIContent, momm.resultPrefab, typeof(GameObject), true);
  214. if (momm is MB3_MeshBaker){
  215. string l = "Mesh";
  216. if (mesh.objectReferenceValue != null) l += " ("+ mesh.objectReferenceValue.GetInstanceID() +")";
  217. EditorGUILayout.PropertyField(mesh,new GUIContent(l));
  218. }
  219. } else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeMeshAssetsInPlace){
  220. EditorGUILayout.HelpBox("NEW! Try the BatchPrefabBaker component. It makes preparing a batch of prefabs for static/ dynamic batching much easier.",MessageType.Info);
  221. if (GUILayout.Button("Choose Folder For Bake In Place Meshes") ){
  222. string newFolder = EditorUtility.SaveFolderPanel("Folder For Bake In Place Meshes", Application.dataPath, "");
  223. if (!newFolder.Contains(Application.dataPath)) Debug.LogWarning("The chosen folder must be in your assets folder.");
  224. momm.bakeAssetsInPlaceFolderPath = "Assets" + newFolder.Replace(Application.dataPath, "");
  225. }
  226. EditorGUILayout.LabelField("Folder For Meshes: " + momm.bakeAssetsInPlaceFolderPath);
  227. }
  228. EditorGUILayout.BeginHorizontal();
  229. EditorGUILayout.PropertyField(clearBuffersAfterBake, gc_clearBuffersAfterBakeGUIContent);
  230. EditorGUILayout.PropertyField(centerMeshToBoundsCenter, gc_CenterMeshToBoundsCenter);
  231. EditorGUILayout.EndHorizontal();
  232. EditorGUILayout.PropertyField(optimizeAfterBake, gc_OptimizeAfterBake);
  233. Color oldColor = GUI.backgroundColor;
  234. GUI.backgroundColor = buttonColor;
  235. if (GUILayout.Button("Bake")){
  236. bake(momm);
  237. }
  238. GUI.backgroundColor = oldColor;
  239. string enableRenderersLabel;
  240. bool disableRendererInSource = false;
  241. if (momm.GetObjectsToCombine().Count > 0){
  242. Renderer r = MB_Utility.GetRenderer(momm.GetObjectsToCombine()[0]);
  243. if (r != null && r.enabled) disableRendererInSource = true;
  244. }
  245. if (disableRendererInSource){
  246. enableRenderersLabel = "Disable Renderers On Source Objects";
  247. } else {
  248. enableRenderersLabel = "Enable Renderers On Source Objects";
  249. }
  250. if (GUILayout.Button(enableRenderersLabel)){
  251. momm.EnableDisableSourceObjectRenderers(!disableRendererInSource);
  252. }
  253. meshBaker.ApplyModifiedProperties();
  254. meshBaker.SetIsDifferentCacheDirty();
  255. }
  256. public static void updateProgressBar(string msg, float progress){
  257. EditorUtility.DisplayProgressBar("Combining Meshes", msg, progress);
  258. }
  259. public static bool bake(MB3_MeshBakerCommon mom){
  260. bool createdDummyTextureBakeResults = false;
  261. bool success = false;
  262. try{
  263. if (mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject ||
  264. mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab)
  265. {
  266. success = MB3_MeshBakerEditorFunctions.BakeIntoCombined(mom, out createdDummyTextureBakeResults);
  267. } else {
  268. //bake meshes in place
  269. if (mom is MB3_MeshBaker){
  270. if (MB3_MeshCombiner.EVAL_VERSION){
  271. Debug.LogError("Bake Meshes In Place is disabled in the evaluation version.");
  272. } else {
  273. MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
  274. if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.prefabOnly, new MB3_EditorMethods(), vl)) return false;
  275. List<GameObject> objsToMesh = mom.GetObjectsToCombine();
  276. success = MB3_BakeInPlace.BakeMeshesInPlace((MB3_MeshCombinerSingle)((MB3_MeshBaker)mom).meshCombiner, objsToMesh, mom.bakeAssetsInPlaceFolderPath, mom.clearBuffersAfterBake, updateProgressBar);
  277. }
  278. } else {
  279. Debug.LogError("Multi-mesh Baker components cannot be used for Bake In Place. Use an ordinary Mesh Baker object instead.");
  280. }
  281. }
  282. mom.meshCombiner.CheckIntegrity();
  283. } catch(Exception e){
  284. Debug.LogError(e);
  285. } finally {
  286. if (createdDummyTextureBakeResults && mom.textureBakeResults != null){
  287. MB_Utility.Destroy(mom.textureBakeResults);
  288. mom.textureBakeResults = null;
  289. }
  290. EditorUtility.ClearProgressBar();
  291. }
  292. return success;
  293. }
  294. }
  295. }