Files
PotionMaker/Assets/MeshBaker/Editor/MB3_MeshBakerEditorFunctions.cs
2026-03-27 16:34:08 +09:00

371 lines
16 KiB
C#

using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using DigitalOpus.MB.Core;
using UnityEditor;
using DigitalOpus.MB.MBEditor;
namespace DigitalOpus.MB.MBEditor
{
public static class MB3_MeshBakerEditorFunctions
{
/// <summary>
/// Used by UnityEditorInspectors for background colors
/// </summary>
public static Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
for (int i = 0; i < pix.Length; i++)
pix[i] = col;
Texture2D result = new Texture2D(width, height);
result.SetPixels(pix);
result.Apply();
return result;
}
public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults)
{
SerializedObject so = null;
return BakeIntoCombined(mom, out createdDummyTextureBakeResults, ref so);
}
/// <summary>
/// Bakes a combined mesh.
/// </summary>
/// <param name="so">If this is being called from Inspector code then pass in the SerializedObject for the component.
/// This is necessary for "bake into prefab" which can corrupt the SerializedObject.</param>
public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults, ref SerializedObject so)
{
MB2_OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption;
createdDummyTextureBakeResults = false;
// Initial Validate
{
if (mom.meshCombiner.resultSceneObject != null &&
(MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.modelPrefabAsset ||
MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.prefabAsset))
{
Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field.");
mom.meshCombiner.resultSceneObject = null;
}
if (prefabOrSceneObject != MB2_OutputOptions.bakeIntoPrefab && prefabOrSceneObject != MB2_OutputOptions.bakeIntoSceneObject)
{
Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject");
return false;
}
if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
{
if (MB3_MeshCombiner.EVAL_VERSION)
{
Debug.LogError("Cannot BakeIntoPrefab with evaluation version.");
return false;
}
if (mom.resultPrefab == null)
{
Debug.LogError("Need to set the Combined Mesh Prefab field. Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field.");
return false;
}
string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab);
if (prefabPth == null || prefabPth.Length == 0)
{
Debug.LogError("Could not save result to prefab. Result Prefab value is not a project asset. Is it an instance in the scene?");
return false;
}
}
}
{
// Find or create texture bake results
MB3_TextureBaker tb = mom.GetComponentInParent<MB3_TextureBaker>();
if (mom.textureBakeResults == null && tb != null)
{
mom.textureBakeResults = tb.textureBakeResults;
}
if (mom.textureBakeResults == null)
{
if (_OkToCreateDummyTextureBakeResult(mom))
{
createdDummyTextureBakeResults = true;
List<GameObject> gos = mom.GetObjectsToCombine();
if (mom.GetNumObjectsInCombined() > 0)
{
if (mom.meshCombiner.clearBuffersAfterBake) { mom.ClearMesh(); }
else
{
Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that already contains objects. Try enabling 'clear buffers after bake'");
return false;
}
}
mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos.ToArray(), mom.meshCombiner.GetMaterialsOnTargetRenderer());
if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("'Texture Bake Result' was not set. Creating a temporary one. Each material will be mapped to a separate submesh."); }
}
}
}
// Second level of validation now that TextureBakeResults exists.
MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.sceneObjOnly, new MB3_EditorMethods(), vl))
{
return false;
}
// Add Delete Game Objects
bool success;
try
{
if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoSceneObject)
{
success = _BakeIntoCombinedSceneObject(mom, createdDummyTextureBakeResults, ref so);
}
else if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
{
success = _BakeIntoCombinedPrefab(mom, createdDummyTextureBakeResults, ref so);
}
else
{
Debug.LogError("Should be impossible.");
success = false;
}
}
catch
{
success = false;
throw;
}
finally
{
mom.meshCombiner.Dispose();
}
if (createdDummyTextureBakeResults) MB_Utility.Destroy(mom.textureBakeResults);
return success;
}
private static bool _BakeIntoCombinedSceneObject(MB3_MeshBakerCommon mom, bool createdDummyTextureBakeResults, ref SerializedObject so)
{
bool success;
mom.ClearMesh();
if (mom.AddDeleteGameObjects(mom.GetObjectsToCombine().ToArray(), null, false) &&
mom.Apply(MB3_MeshBakerEditorFunctionsCore.UnwrapUV2))
{
success = true;
if (createdDummyTextureBakeResults)
{
Debug.Log(String.Format("Successfully baked {0} meshes each material is mapped to its own submesh.", mom.GetObjectsToCombine().Count));
}
else
{
Debug.Log(String.Format("Successfully baked {0} meshes", mom.GetObjectsToCombine().Count));
}
}
else
{
success = false;
}
return success;
}
private static bool _BakeIntoCombinedPrefab(MB3_MeshBakerCommon mom, bool createdDummyTextureBakeResults, ref SerializedObject so)
{
bool success = false;
List<Transform> tempPrefabInstanceRoots = null;
GameObject[] objsToCombine = mom.GetObjectsToCombine().ToArray();
if (mom.meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer)
{
tempPrefabInstanceRoots = new List<Transform>();
// We are going to move bones of source objs and transforms into our combined mesh prefab so make some duplicates
// so that we don't destroy a setup.
MB3_MeshBakerEditorFunctionsCore._DuplicateSrcObjectInstancesAndUnpack(mom.meshCombiner.settings.renderType, objsToCombine, tempPrefabInstanceRoots);
}
try
{
MB3_EditorMethods editorMethods = new MB3_EditorMethods();
mom.ClearMesh(editorMethods);
if (mom.AddDeleteGameObjects(objsToCombine, null, false))
{
success = true;
mom.Apply(MB3_MeshBakerEditorFunctionsCore.UnwrapUV2);
if (createdDummyTextureBakeResults)
{
Debug.Log(String.Format("Successfully baked {0} meshes each material is mapped to its own submesh.", mom.GetObjectsToCombine().Count));
}
else
{
Debug.Log(String.Format("Successfully baked {0} meshes", mom.GetObjectsToCombine().Count));
}
string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab);
if (prefabPth == null || prefabPth.Length == 0)
{
Debug.LogError("Could not save result to prefab. Result Prefab value is not an Asset.");
success = false;
}
else
{
string baseName = Path.GetFileNameWithoutExtension(prefabPth);
string folderPath = prefabPth.Substring(0, prefabPth.Length - baseName.Length - 7);
string newFilename = folderPath + baseName + "-mesh";
SaveMeshsToAssetDatabase(mom, folderPath, newFilename);
RebuildPrefab(mom, ref so, mom.resultPrefabLeaveInstanceInSceneAfterBake, tempPrefabInstanceRoots, objsToCombine);
}
}
else
{
success = false;
}
}
catch
{
throw;
}
finally
{
// Clean up temporary created instances. If success was true then they should have been added to a prefab
// and cleaned up for us.
if (success == false)
{
if (tempPrefabInstanceRoots != null)
{
for (int i = 0; i < tempPrefabInstanceRoots.Count; i++)
{
MB_Utility.Destroy(tempPrefabInstanceRoots[i]);
}
}
}
}
return success;
}
public static bool _OkToCreateDummyTextureBakeResult(MB3_MeshBakerCommon mom)
{
List<GameObject> objsToMesh = mom.GetObjectsToCombine();
if (objsToMesh.Count == 0)
return false;
return true;
}
public static void SaveMeshsToAssetDatabase(MB3_MeshBakerCommon mom, string folderPath, string newFileNameBase)
{
if (MB3_MeshCombiner.EVAL_VERSION) return;
if (mom is MB3_MeshBaker)
{
MB3_MeshBaker mb = (MB3_MeshBaker)mom;
string newFilename = newFileNameBase + ".asset";
string ap = AssetDatabase.GetAssetPath(((MB3_MeshCombinerSingle)mb.meshCombiner).GetMesh());
if (ap == null || ap.Equals(""))
{
Debug.Log("Saving mesh asset to " + newFilename);
AssetDatabase.CreateAsset(((MB3_MeshCombinerSingle)mb.meshCombiner).GetMesh(), newFilename);
}
else
{
Debug.Log("Mesh is an existing asset at " + ap);
}
}
else if (mom is MB3_MultiMeshBaker)
{
MB3_MultiMeshBaker mmb = (MB3_MultiMeshBaker)mom;
List<MB3_MultiMeshCombiner.CombinedMesh> combiners = ((MB3_MultiMeshCombiner)mmb.meshCombiner).meshCombiners;
for (int i = 0; i < combiners.Count; i++)
{
string newFilename = newFileNameBase + i + ".asset";
Mesh mesh = combiners[i].combinedMesh.GetMesh();
string ap = AssetDatabase.GetAssetPath(mesh);
if (ap == null || ap.Equals(""))
{
Debug.Log("Saving mesh asset to " + newFilename);
AssetDatabase.CreateAsset(mesh, newFilename);
}
else
{
Debug.Log("Mesh is an asset at " + ap);
}
}
}
else
{
Debug.LogError("Argument was not a MB3_MeshBaker or an MB3_MultiMeshBaker.");
}
}
// The serialized object reference is necessary to work around a nasty unity bug.
public static GameObject RebuildPrefab(MB3_MeshBakerCommon mom, ref SerializedObject so, bool leaveInstanceInSceneAfterBake, List<Transform> tempPrefabInstanceRoots, GameObject[] objsToCombine)
{
if (MB3_MeshCombiner.EVAL_VERSION) return null;
if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Rebuilding Prefab: " + mom.resultPrefab);
GameObject prefabRoot = mom.resultPrefab;
GameObject instanceRootGO = mom.meshCombiner.resultSceneObject;
/*
GameObject instanceRootGO = (GameObject)PrefabUtility.InstantiatePrefab(prefabRoot);
instanceRootGO.transform.position = Vector3.zero;
instanceRootGO.transform.rotation = Quaternion.identity;
instanceRootGO.transform.localScale = Vector3.one;
//remove everything in the prefab.
MBVersionEditor.UnpackPrefabInstance(instanceRootGO, ref so);
int numChildren = instanceRootGO.transform.childCount;
for (int i = numChildren - 1; i >= 0; i--)
{
MB_Utility.Destroy(instanceRootGO.transform.GetChild(i).gameObject);
}
if (mom is MB3_MeshBaker)
{
MB3_MeshBaker mb = (MB3_MeshBaker)mom;
MB3_MeshCombinerSingle mbs = (MB3_MeshCombinerSingle)mb.meshCombiner;
MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs, instanceRootGO, mbs.GetMesh());
}
else if (mom is MB3_MultiMeshBaker)
{
MB3_MultiMeshBaker mmb = (MB3_MultiMeshBaker)mom;
MB3_MultiMeshCombiner mbs = (MB3_MultiMeshCombiner)mmb.meshCombiner;
for (int i = 0; i < mbs.meshCombiners.Count; i++)
{
MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs.meshCombiners[i].combinedMesh, instanceRootGO, mbs.meshCombiners[i].combinedMesh.GetMesh(), true);
}
}
else
{
Debug.LogError("Argument was not a MB3_MeshBaker or an MB3_MultiMeshBaker.");
}
*/
if (mom.meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer)
{
MB3_MeshBakerEditorFunctionsCore._MoveBonesToCombinedMeshPrefabAndDeleteRenderers(instanceRootGO.transform, tempPrefabInstanceRoots, objsToCombine);
}
string prefabPth = AssetDatabase.GetAssetPath(prefabRoot);
MBVersionEditor.PrefabUtility_ReplacePrefab(instanceRootGO, prefabPth, MB_ReplacePrefabOption.connectToPrefab);
mom.resultPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPth);
if (!leaveInstanceInSceneAfterBake)
{
Editor.DestroyImmediate(instanceRootGO);
}
return instanceRootGO;
}
}
}