test : opti

This commit is contained in:
Ferlat Thibaud
2026-07-03 11:49:25 +02:00
parent 85ab8ebabd
commit fea082bb6f
399 changed files with 1912806 additions and 1893 deletions
+5
View File
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: bed2530773cba054c89b4104ccef2743
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,244 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using DigitalOpus.MB.Core;
using System.Text.RegularExpressions;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_BatchPrefabBaker))]
public class MB3_BatchPrefabBakerEditor : Editor
{
SerializedObject prefabBaker = null;
GUIContent GUIContentLogLevelContent = new GUIContent("Log Level");
GUIContent GUIContentBatchBakePrefabReplacePrefab = new GUIContent("Batch Bake Prefabs (Replace Prefab)",
"This will clone the source prefab, replace the meshes in the clone with baked versions, and replace the target prefab with the clone.\n\n" +
"IF ANY CHANGES HAD BEEN MADE TO THE TARGET PREFAB, THOSE WILL BE LOST.");
GUIContent GUIContentBatchBakePrefabOnlyMeshesAndMats = new GUIContent("Batch Bake Prefabs (Only Replace Meshes & Materials)",
"This will attempt to match the meshes used by the target prefab to those used by the source prefab. For this to work well," +
" the source and target prefabs should have the same hierarchy. The meshes and materials in the target prefab will be updated to baked versions." +
" Modifications to the target prefab other than the meshes and materials will be preserved.\n\n" +
"Check the console for errors after baking the prefabs.");
SerializedProperty prefabRows, outputFolder, logLevel;
private int prefabRows_CurrentPage = 1;
private int prefabRows_NumPerPage = 50;
Color buttonColor = new Color(.8f, .8f, 1f, 1f);
[MenuItem("GameObject/Create Other/Mesh Baker/Batch Prefab Baker", false, 1000)]
public static void CreateNewBatchPrefabBaker()
{
//if (MB3_MeshCombiner.EVAL_VERSION)
//{
// Debug.LogError("The prefab baker is only available in the full version of MeshBaker.");
// return;
//}
MB3_TextureBaker[] mbs = (MB3_TextureBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_TextureBaker));
// Generate unique name
int largest = 0;
{
Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
try
{
for (int i = 0; i < mbs.Length; i++)
{
Match match = regex.Match(mbs[i].name);
if (match.Success)
{
int val = Convert.ToInt32(match.Groups[1].Value);
if (val >= largest)
largest = val + 1;
}
}
}
catch (Exception e)
{
if (e == null) e = null; //Do nothing supress compiler warning
}
}
GameObject nmb = new GameObject("BatchPrefabBaker (" + largest + ")");
nmb.transform.position = Vector3.zero;
MB3_BatchPrefabBaker bpb = nmb.AddComponent<MB3_BatchPrefabBaker>();
nmb.AddComponent<MB3_TextureBaker>();
nmb.AddComponent<MB3_MeshBaker>();
bpb.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
bpb.outputPrefabFolder = "";
}
void OnEnable()
{
prefabBaker = new SerializedObject(target);
prefabRows = prefabBaker.FindProperty("prefabRows");
outputFolder = prefabBaker.FindProperty("outputPrefabFolder");
logLevel = prefabBaker.FindProperty("LOG_LEVEL");
}
void OnDisable()
{
prefabBaker = null;
}
public override void OnInspectorGUI()
{
prefabBaker.Update();
EditorGUILayout.HelpBox(
"This tool speeds up the process of preparing prefabs" +
" for static and dynamic batching. It creates duplicate prefab assets and meshes" +
" that share a combined material. Source assets are not touched.\n\n" +
"1) Create instances of source prefabs to this scene.\n" +
"2) Add these instances to the TextureBaker on this GameObject and bake the textures used by the prefabs.\n" +
"3) Using the BatchPrefabBaker component, click 'Populate Prefab Rows From Texture Baker' or manually set up Prefab Rows by dragging to the Prefab Rows list.\n" +
"4) Choose a folder where the result prefabs will be stored and click 'Create Empty Result Prefabs'\n" +
"5) Click 'Batch Bake Prefabs'\n" +
"6) Check the console for messages and errors\n" +
"7) (Optional) If you want to compare the source objects to the result objects use the BatchPrefabBaker '...' menu command 'Create Instances For Prefab Rows'. This will create aligned instances of the prefabs in the scene so that it is easy to see any differences.\n", MessageType.Info);
EditorGUILayout.PropertyField(logLevel, GUIContentLogLevelContent);
MB_PaginatedList.GenerateObjectsToBeCombinedList(prefabRows, ref prefabRows_CurrentPage, ref prefabRows_NumPerPage);
EditorGUILayout.LabelField("Output Folder", EditorStyles.boldLabel);
EditorGUILayout.LabelField(outputFolder.stringValue);
if (GUILayout.Button("Browse For Output Folder"))
{
string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
path = MB_BatchPrefabBakerEditorFunctionsCore.ConvertFullPathToProjectRelativePath(path);
outputFolder.stringValue = path;
}
if (GUILayout.Button("Create Empty Result Prefabs"))
{
MB_BatchPrefabBakerEditorFunctions.CreateEmptyOutputPrefabs(outputFolder.stringValue, (MB3_BatchPrefabBaker) target);
}
Color oldColor = GUI.backgroundColor;
GUI.backgroundColor = buttonColor;
if (GUILayout.Button(GUIContentBatchBakePrefabReplacePrefab))
{
MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, true);
}
if (GUILayout.Button(GUIContentBatchBakePrefabOnlyMeshesAndMats))
{
MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, false);
}
GUI.backgroundColor = oldColor;
if (GUILayout.Button("Populate Prefab Rows From Texture Baker"))
{
PopulatePrefabRowsFromTextureBaker((MB3_BatchPrefabBaker)prefabBaker.targetObject);
}
if (GUILayout.Button("Open Replace Prefabs In Scene Window"))
{
MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
MB_ReplacePrefabsInSceneEditorWindow.ShowWindow(pb.prefabRows);
}
prefabBaker.ApplyModifiedProperties();
prefabBaker.SetIsDifferentCacheDirty();
}
public void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
{
MB3_TextureBaker texBaker = prefabBaker.GetComponent<MB3_TextureBaker>();
List<GameObject> newPrefabs = new List<GameObject>();
List<GameObject> gos = texBaker.GetObjectsToCombine();
for (int i = 0; i < gos.Count; i++)
{
if (gos[i] == null)
{
Debug.LogError("Prefab in Objects To Be Combined at index " + i + " is null. Make sure that all objects to be batched are non-null prefabs.");
return;
}
GameObject go = (GameObject)MBVersionEditor.PrefabUtility_FindPrefabRoot(gos[i]);
if (go == null)
{
Debug.LogError("Could not find prefab root for " + gos[i] + " at index " + i + ". Make sure that all objects to be batched are non-null prefabs.");
return;
}
UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);
if (obj != null && obj is GameObject)
{
if (!newPrefabs.Contains((GameObject)obj)) newPrefabs.Add((GameObject)obj);
}
else
{
Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
}
}
// Remove prefabs that are already in the list of batch prefab baker's prefabs.
{
List<GameObject> tmpNewPrefabs = new List<GameObject>();
for (int i = 0; i < newPrefabs.Count; i++)
{
bool found = false;
for (int j = 0; j < prefabBaker.prefabRows.Length; j++)
{
if (prefabBaker.prefabRows[j].sourcePrefab == newPrefabs[i])
{
found = true;
break;
}
}
if (!found)
{
tmpNewPrefabs.Add(newPrefabs[i]);
}
}
newPrefabs = tmpNewPrefabs;
}
if (MB3_MeshCombiner.EVAL_VERSION)
{
int numPrefabsLimit = MB_BatchPrefabBakerEditorFunctions.EvalVersionPrefabLimit;
int numNew = numPrefabsLimit - prefabBaker.prefabRows.Length;
if (newPrefabs.Count + prefabBaker.prefabRows.Length > numPrefabsLimit)
{
Debug.LogError("The free version of Mesh Baker is limited to batch baking " + numPrefabsLimit +
" prefabs. The full version has no limit on the number of prefabs that can be baked. " + (newPrefabs.Count - numNew) + " prefabs were not added.");
}
for (int i = newPrefabs.Count - 1; i >= numNew; i--)
{
newPrefabs.RemoveAt(i);
}
}
List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();
if (prefabBaker.prefabRows == null) prefabBaker.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
newRows.AddRange(prefabBaker.prefabRows);
for (int i = 0; i < newPrefabs.Count; i++)
{
MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
row.sourcePrefab = newPrefabs[i];
newRows.Add(row);
}
Undo.RecordObject(prefabBaker, "Populate prefab rows");
prefabBaker.prefabRows = newRows.ToArray();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 9eec7d996f61d7245a9c9d169979b8dd
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_BatchPrefabBakerEditor.cs
uploadId: 797180
@@ -0,0 +1,337 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2015-2016 Ian Deane
//----------------------------------------------
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;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_BoneWeightCopier))]
public class MB3_BoneWeightCopierEditor : Editor
{
SerializedProperty inputGameObjectProp;
SerializedProperty outputPrefabProp;
SerializedProperty radiusProp;
SerializedProperty seamMeshProp;
SerializedProperty targetMeshesProp;
SerializedProperty outputFolderProp;
GameObject copyOfInput;
GUIContent gc_inputGameObject = new GUIContent("Input Game Object", "Assign the parent object of all the Skinned Meshes to this field.");
GUIContent gc_outputPrefab = new GUIContent("Output Prefab", "Provide a GameObject Prefab that the Bone Weight Copier will output to.");
GUIContent gc_radius = new GUIContent("Radius", "Vertices in each Target Mesh that are within Radius of a vertex in the Seam Mesh will be assigned the same bone weight as the Seam Mesh vertex.");
GUIContent gc_seamMesh = new GUIContent("Seam Mesh", "The seam mesh should contain vertices for the seams with correct bone weights. Seams are the vertices that are shared by two skinned meshes that overlap. For example there should be a seam between an arm skinned mesh and a hand skinned mesh.");
GUIContent gc_outputFolder = new GUIContent("Output Folder", "Copies of the Skinned Meshes will be saved to this folder, must be located in the project Assets folder.");
[MenuItem("GameObject/Create Other/Mesh Baker/Bone Weight Copier", false, 1000)]
public static GameObject CreateNewMeshBaker()
{
GameObject nmb = new GameObject("BoneWeightCopier");
nmb.transform.position = Vector3.zero;
nmb.AddComponent<MB3_BoneWeightCopier>();
return nmb.gameObject;
}
void OnEnable()
{
radiusProp = serializedObject.FindProperty("radius");
seamMeshProp = serializedObject.FindProperty("seamMesh");
//targetMeshesProp = serializedObject.FindProperty("targetMeshes");
outputFolderProp = serializedObject.FindProperty("outputFolder");
inputGameObjectProp = serializedObject.FindProperty("inputGameObject");
outputPrefabProp = serializedObject.FindProperty("outputPrefab");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
MB3_BoneWeightCopier bwc = (MB3_BoneWeightCopier)target;
EditorGUILayout.HelpBox("== BETA (please report problems) ==\n\n" +
"This tool helps create skinned mesh parts that can be mix and matched to customize characters. " +
"It adjusts the boneWeights, positions, normals and tangents at the joins to have the same values so there are no tears." +
"\n\n" +
"1) Model the skinned meshes and attach them all to the same rig. The rig may have multiple arms, hands, hair etc...\n" +
"2) At every seam (eg. between an arm mesh and hand mesh) there must be a set of vertices duplicated in both meshes.\n" +
"3) Create one additional mesh that contains another copy of all the geometry. This will be called the Seam Mesh\n" +
"4) Attach it to the rig and adjust the bone weights. This will be the master set of bone weights that will be copied to all the other skinned meshes.\n" +
"5) Mark the seam vertices using the UV channel.\n" +
" verts with UV > (.5,.5) are seam verts\n" +
" verts with UV < (.5,.5) are ignored\n" +
"6) Import the model into Unity and create an instance of it in the scene\n" +
"7) Assign the Seam Mesh to the Seam Mesh field\n" +
"8) Assign the parent game object of all the skinned meshes to the Input Game Object field\n" +
"9) Adjust the radius\n" +
"10) Choose an output folder and save the meshes\n" +
"11) Click 'Copy Bone Weights From Seam Mesh'\n", MessageType.Info);
EditorGUILayout.PropertyField(radiusProp, gc_radius);
EditorGUILayout.PropertyField(seamMeshProp, gc_seamMesh);
EditorGUILayout.PropertyField(inputGameObjectProp, gc_inputGameObject);
EditorGUILayout.PropertyField(outputPrefabProp, gc_outputPrefab);
//if (GUILayout.Button("Get Skinned Meshes From Input Game Object")) {
// GetSkinnedMeshesFromGameObject(bwc);
//}
//EditorGUILayout.PropertyField(targetMeshesProp,true);
if (GUILayout.Button("Copy Bone Weights From Seam Mesh"))
{
CopyBoneWeightsFromSeamMeshToOtherMeshes(bwc);
}
EditorGUILayout.Separator();
EditorGUILayout.Separator();
EditorGUILayout.LabelField("Save Meshes To Project Folder", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(outputFolderProp, gc_outputFolder);
bool pathIsValid;
string errorMessage;
{
string path = outputFolderProp.stringValue;
outputFolderProp.stringValue =
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(path, out errorMessage,
out pathIsValid);
Debug.Assert(errorMessage != null, "errorMessage should never be null");
}
if (GUILayout.Button("Browse"))
{
string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
path = MB_BatchPrefabBakerEditorFunctionsCore.ConvertFullPathToProjectRelativePath(path);
outputFolderProp.stringValue = path;
}
EditorGUILayout.EndHorizontal();
if (!pathIsValid)
{
EditorGUILayout.HelpBox(errorMessage, MessageType.Error);
}
if (GUILayout.Button("Set Output Folder To Output Prefab Folder"))
{
string path = AssetDatabase.GetAssetPath(bwc.outputPrefab);
path = new System.IO.FileInfo(path).Directory.FullName.Replace('\\', '/');
path = MB_BatchPrefabBakerEditorFunctionsCore.ConvertFullPathToProjectRelativePath(path);
outputFolderProp.stringValue = path;
}
serializedObject.ApplyModifiedProperties();
}
public void CopyBoneWeightsFromSeamMeshToOtherMeshes(MB3_BoneWeightCopier bwc)
{
if (bwc.seamMesh == null)
{
Debug.LogError("The Seam Mesh cannot be null.");
return;
}
if (bwc.inputGameObject == null)
{
Debug.LogError("The Input Game Object cannot be null.");
return;
}
UnityEngine.Object pr = (UnityEngine.Object) MBVersionEditor.PrefabUtility_FindPrefabRoot(bwc.seamMesh.gameObject);
string assetPath = null;
if (pr != null)
{
assetPath = AssetDatabase.GetAssetPath(pr);
}
if (assetPath != null)
{
ModelImporter mi = (ModelImporter)AssetImporter.GetAtPath(assetPath);
if (mi != null)
{
if (mi.optimizeGameObjects)
{
Debug.LogError(string.Format("The seam mesh has 'optimize game objects' checked in the asset importer rig tab. This will result in no bones. Uncheck 'optimize game objects' in the rig tab."));
return;
}
}
}
{
// Check that inputGameObject contains all the bones;
Transform[] bones = bwc.seamMesh.bones;
for (int i = 0; i < bones.Length; i++)
{
Transform b = bones[i];
if (b == null)
{
Debug.LogError("There are null bones on the seam mesh.");
return;
} else
{
if (!IsChildOf(bwc.inputGameObject.transform, b))
{
Debug.LogError("All bones used by the seam mesh must be children of the Input Game Object. There were some bones that were not a children of the seam mesh.");
return;
}
}
}
}
if (bwc.outputPrefab == null)
{
Debug.LogError(string.Format("The output game object must be assigned and must be a prefab of a game object in the project folder."));
return;
}
if (MBVersionEditor.PrefabUtility_GetPrefabType(bwc.outputPrefab) != MB_PrefabType.prefabAsset)
{
Debug.LogError("The output game object must be a prefab. Create a prefab in the project and drag an empty game object to it.");
return;
}
//duplicate the source prefab and the meshes
if (copyOfInput != null)
{
DestroyImmediate(copyOfInput);
}
copyOfInput = (GameObject)GameObject.Instantiate(bwc.inputGameObject);
Transform seamMeshCopyTransform = MB_BatchPrefabBakerEditorFunctionsCore.FindCorrespondingTransform(bwc.inputGameObject.transform, bwc.seamMesh.transform, copyOfInput.transform);
SkinnedMeshRenderer seamMeshCopy = seamMeshCopyTransform.GetComponent<SkinnedMeshRenderer>();
Transform[] seamMeshBones = seamMeshCopy.bones;
SkinnedMeshRenderer[] targSkinnedMeshes = copyOfInput.GetComponentsInChildren<SkinnedMeshRenderer>();
Transform[][] targMeshBones = new Transform[targSkinnedMeshes.Length][];
Mesh[] targs = new Mesh[targSkinnedMeshes.Length];
for (int i = 0; i < targSkinnedMeshes.Length; i++)
{
if (targSkinnedMeshes[i].sharedMesh == null)
{
Debug.LogError(string.Format("Skinned Mesh {0} does not have a mesh", targSkinnedMeshes[i]));
return;
}
MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(targSkinnedMeshes[i].gameObject);
if (pt == MB_PrefabType.modelPrefabAsset)
{
Debug.LogError(string.Format("Target Mesh {0} is an imported model prefab. Can't modify these meshes because changes will be overwritten the next time the model is saved or reimported. Try instantiating the prefab and using skinned meshes from the scene instance.", i));
return;
}
targMeshBones[i] = targSkinnedMeshes[i].bones;
targs[i] = (Mesh)GameObject.Instantiate(targSkinnedMeshes[i].sharedMesh);
}
Transform[][] newBonesForSMRs = new Transform[targs.Length][];
MB3_CopyBoneWeights.CopyBoneWeightsFromSeamMeshToOtherMeshes(bwc.radius, seamMeshCopy.sharedMesh, targs, newBonesForSMRs, seamMeshBones, targMeshBones);
SaveMeshesToOutputFolderAndAssignToSMRs(targs, newBonesForSMRs, targSkinnedMeshes);
EditorUtility.SetDirty(copyOfInput);
// TODO tried using 2018 replace prefab but there were errors.
//MBVersionEditor.ReplacePrefab(copyOfInput, assetPath, MB_ReplacePrefabOption.connectToPrefab | MB_ReplacePrefabOption.nameBased);
string prefabPth = AssetDatabase.GetAssetPath(bwc.outputPrefab);
MBVersionEditor.PrefabUtility_ReplacePrefab(copyOfInput, prefabPth, MB_ReplacePrefabOption.connectToPrefab | MB_ReplacePrefabOption.nameBased);
AssetDatabase.SaveAssets();
DestroyImmediate(copyOfInput);
}
public void SaveMeshesToOutputFolderAndAssignToSMRs(Mesh[] targetMeshes, Transform[][] newBonesForSMRs, SkinnedMeshRenderer[] targetSMRs)
{
Debug.Assert(targetMeshes.Length == newBonesForSMRs.Length);
//validate meshes
for (int i = 0; i < targetMeshes.Length; i++)
{
if (targetMeshes[i] == null)
{
Debug.LogError(string.Format("An error occured processing mesh {0}. Mesh could not be saved.", targetSMRs[i]));
continue;
}
if (targetSMRs[i] == null)
{
Debug.LogError(string.Format("Target SkinnedMesh {0} is null", i));
return;
}
if (targetSMRs[i].sharedMesh == null)
{
Debug.LogError(string.Format("Target Mesh {0} does not have a mesh", i));
return;
}
MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(targetMeshes[i]);
if (pt == MB_PrefabType.modelPrefabAsset)
{
Debug.LogError(string.Format("Target Mesh {0} is an imported model prefab. Can't modify these meshes because changes will be overwritten the next time the model is saved or reimported. Try instantiating the prefab and using skinned meshes from the scene instance.", i));
return;
}
}
//validate output folder
if (outputFolderProp.stringValue == null)
{
Debug.LogError("Output folder must be set");
return;
}
else
{
{
string errorMessage;
bool pathIsValid;
outputFolderProp.stringValue =
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(
outputFolderProp.stringValue, out errorMessage, out pathIsValid);
if (!pathIsValid)
{
Debug.LogError(errorMessage);
return;
}
}
}
for (int i = 0; i < targetMeshes.Length; i++)
{
Mesh m = targetMeshes[i];
if (m == null)
{
continue;
}
string pth = outputFolderProp.stringValue + "/" + targetMeshes[i].name + ".Asset";
if (pth == null)
{
Debug.LogError("The output folder must be a folder in the project Assets folder.");
return;
}
Debug.Log("Creating mesh " + m + " path " + pth + " numBindPoses: " + m.bindposes.Length + " targSMRs numBones: " + targetSMRs[i].bones.Length);
targetSMRs[i].sharedMesh = m;
if (newBonesForSMRs[i] != null) targetSMRs[i].bones = newBonesForSMRs[i];
AssetDatabase.CreateAsset(m, pth);
targetSMRs[i].sharedMesh = m;
Debug.Log(string.Format("Created mesh at {0}. Updated Skinned Mesh {1} to use created mesh.", pth, targetSMRs[i].name));
}
AssetDatabase.SaveAssets();
}
bool IsChildOf(Transform parent, Transform child)
{
if (parent == null) return false;
if (child == null) return false;
Transform t = child.parent;
do
{
if (t == parent || t.parent == parent)
{
return true;
}
t = t.parent;
} while (t != child.root);
return false;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 0a5f54a19161b7e489e7c1815bb56b79
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_BoneWeightCopierEditor.cs
uploadId: 797180
@@ -0,0 +1,374 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2024 Ian Deane
//----------------------------------------------
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
/// <summary>
/// MB3_ColorTintTextureGenerator handles all the logic for the MB3_CreateCOlorTintWindow class.
///
/// Provides functionality for detecting materials which are candidates for color tint texture generation and for performing this generation.
///
/// Makes use of the ColorTintTextureData structure which is also defined in this file to pass information to the MB3_CreateColorTintWindow class.
/// </summary>
public class MB3_ColorTintTextureGenerator
{
public struct ColorTintTextureData
{
public Material mat;
public bool willGenerateColorTexture;
public bool hasColorProperty;
public bool hasTextureProperty;
public Color colorProperty;
public Texture textureProperty;
public List<string> messages;
}
private MB3_TextureBaker textureBaker;
private Dictionary<Color, string> color2TexMap;
public MB3_ColorTintTextureGenerator(MB3_TextureBaker tb)
{
textureBaker = tb;
color2TexMap = new Dictionary<Color, string>();
}
public List<ColorTintTextureData> GenerateColorTintTextures(MB3_TextureBaker tb, List<ColorTintTextureData> ctData,
string path, int texSize,
string[] colorProps, string[] albedoProps,
bool applyChanges, out List<string> fileNames)
{
// validate inputs
if (textureBaker == null)
{
string errorMsg = "Texture baker is not set. This operation requires a texture baker reference.";
throw new Exception(errorMsg);
}
else if (tb != textureBaker)
{
string errorMsg = "Selected texture baker has changed since material list was found.\nPlease find color tint textures again before attempting to generate.";
throw new Exception(errorMsg);
}
if (applyChanges && (path == null || path == ""))
{
string errorMsg = "Folder path must be selected before color tint textures can be generated.";
throw new Exception(errorMsg);
}
if (applyChanges && ctData == null)
{
string errorMsg = "Color tint textures must be found before color tint textures can be generated. Please click \'Find Color Tint Textures\' first.\nThis error may occur if texture baker is changed after color tint textures are found.";
throw new Exception(errorMsg);
}
if (!MB3_MeshBakerRoot.ValidateTextureBakerGameObjects(textureBaker,
textureBaker.GetObjectsToCombine(),
MB2_ValidationLevel.quick))
{
string errorMsg = "Something went wrong when validating the game objects belonging to the texture baker." +
"Double check that your texture baker is set up correctly.";
throw new Exception(errorMsg);
}
// check if we have at least one colorprop and one albedoprop to search for
if (colorProps.Length <= 0)
{
string errorMsg = "No color properties provided." +
"There must be at least one color property present in the array.";
throw new Exception(errorMsg);
}
else
{
for (int i = 0; i < colorProps.Length; i++)
{
if (colorProps[i] == "")
{
string errorMsg = "One or more of your color properties is empty." +
"Please ensure all properties have an assigned string.";
throw new Exception(errorMsg);
}
}
}
if (albedoProps.Length <= 0)
{
string errorMsg = "No albedo properties provided." +
"There must be at least one albedo property present in the array.";
throw new Exception(errorMsg);
}
else
{
for (int i = 0; i < albedoProps.Length; i++)
{
if (albedoProps[i] == "")
{
string errorMsg = "One or more of your albedo properties is empty." +
"Please ensure all properties have an assigned string.";
throw new Exception(errorMsg);
}
}
}
List<GameObject> objsToCombine = textureBaker.GetObjectsToCombine();
// check that objects have been added to texture baker
if (objsToCombine.Count == 0)
{
string errorMsg = "No game objects have been added to the selected Texture Baker.";
throw new Exception(errorMsg);
}
// handle initializations
List<ColorTintTextureData> dataList = new List<ColorTintTextureData>();
fileNames = new List<string>();
color2TexMap.Clear();
// retrieve materials from ObjectsToCombine
List<Material> matsToCombine = new List<Material>();
for (int i = 0; i < objsToCombine.Count; i++)
{
matsToCombine.AddRange(objsToCombine[i].GetComponent<Renderer>().sharedMaterials.ToList());
}
// ensure our material list does not contain duplicates
matsToCombine = matsToCombine.Distinct().ToList();
//do validation on materials
for (int i = matsToCombine.Count - 1; i >= 0; i--)
{
ColorTintTextureData data = new ColorTintTextureData
{
messages = new List<string>(),
willGenerateColorTexture = true,
mat = matsToCombine[i]
};
Material mat = matsToCombine[i];
// check if material is null
if (mat == null)
{
data.willGenerateColorTexture = false;
data.messages.Add("Material was null.");
matsToCombine.Remove(mat);
}
else if (!AssetDatabase.GetAssetPath(mat).Contains("Assets"))
{
data.willGenerateColorTexture = false;
data.messages.Add("Material was not in the \'Assets\' folder: " + mat);
matsToCombine.Remove(mat);
}
else
{
// check if material has no albedo texture or color tint (remove from list)
data.hasColorProperty = false;
data.hasTextureProperty = false;
data.colorProperty = GetColorFromMaterial(mat, colorProps, out data.hasColorProperty);
data.textureProperty = GetTextureFromMaterial(mat, albedoProps, out data.hasTextureProperty);
if (!data.hasColorProperty)
{
data.willGenerateColorTexture = false;
data.messages.Add("Color property could not be detected.");
}
if (!data.hasTextureProperty)
{
data.willGenerateColorTexture = false;
data.messages.Add("Texture property could not be detected.");
}
else
{
// if material has texture property field the value of that field must be null or mat will be removed
if (data.textureProperty != null)
{
data.willGenerateColorTexture = false;
data.messages.Add("Material " + mat + "already has albedo texture in detected texture property.");
}
}
if (!data.willGenerateColorTexture)
{
matsToCombine.Remove(mat);
}
}
dataList.Add(data);
}
if (applyChanges)
{
// get unique colors
List<Color> colorsOnMats = new List<Color>();
Undo.RecordObjects(matsToCombine.ToArray(), "Color Tint Texture Generation");
for (int i = 0; i < matsToCombine.Count; i++)
{
Material mat = matsToCombine[i];
if (mat != null)
{
Color tintColor;
bool foundColor;
tintColor = GetColorFromMaterial(mat, colorProps, out foundColor);
// at this point we should be able to assume that the material has a color associated with one of our property names
Debug.Assert(foundColor, "Expected material " + mat + " to have a detectable color property but none was found.");
colorsOnMats.Add(tintColor);
}
}
colorsOnMats = colorsOnMats.Distinct().ToList();
for (int i = 0; i < colorsOnMats.Count; i++)
{
Color tintColor = colorsOnMats[i];
Texture2D tintTexture;
if (!color2TexMap.ContainsKey(tintColor))
{
string filePath = BuildAndSaveColorTintTexture(path, "ColorTintTexture" + i, texSize, tintColor, out tintTexture);
fileNames.Add(filePath);
color2TexMap.Add(tintColor, filePath);
}
}
AssignTintTexturesToMaterials(matsToCombine, colorProps, albedoProps);
return dataList;
}
else
{
return dataList;
}
}
private string BuildAndSaveColorTintTexture(string path, string fileName, int texSize,
Color tintColor, out Texture2D tintTexture)
{
// create size by size texture filled with 'color' pixels
bool linear = false;
switch (PlayerSettings.colorSpace)
{
case ColorSpace.Uninitialized:
string errorMsg = "Project color space is not initialized. Could not generate 2D textures";
throw new Exception(errorMsg);
case ColorSpace.Gamma:
linear = false;
break;
case ColorSpace.Linear:
linear = true;
break;
}
tintTexture = new Texture2D(texSize, texSize, TextureFormat.RGBA32, true, linear);
Color[] pixels = new Color[texSize * texSize];
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = tintColor;
}
tintTexture.SetPixels(pixels);
tintTexture.Apply();
// save texture as file in 'path' folder
string filePath = path + "/" + fileName + ".asset";
filePath = AssetDatabase.GenerateUniqueAssetPath(filePath);
// Write the PNG texture data to a file
AssetDatabase.CreateAsset(tintTexture, filePath);
return filePath;
}
private void AssignTintTexturesToMaterials(List<Material> mats, string[] colorProps, string[] albedoProps)
{
// visit each source material
for (int i = 0; i < mats.Count; i++)
{
Material mat = mats[i];
if (mat != null)
{
// get color tint
bool foundColor;
Color tintColor = GetColorFromMaterial(mat, colorProps, out foundColor);
Debug.Assert(foundColor, "Expected material " + mat + " to have a detectable color property but none was found.");
// feed color tint into dictionary and assign corresponding texture to material
string texturePath = color2TexMap[tintColor];
Texture2D textureToAssign = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
bool foundTexture;
SetMaterialTexture(mat, albedoProps, textureToAssign, out foundTexture);
Debug.Assert(foundTexture, "Expected material " + mat + " to have detectable texture property but none was found.");
SetMaterialColorToDefault(mat, colorProps, out foundColor);
Debug.Assert(foundColor, "Material " + mat + " had detectable material property when fetching color but not when setting color.");
}
}
}
private Color GetColorFromMaterial(Material mat, string[] colorProperties, out bool foundColor)
{
Color color = new Color();
for (int i = 0; i < colorProperties.Length; i++)
{
string prop = colorProperties[i];
if (mat.HasProperty(prop))
{
color = mat.GetColor(prop);
foundColor = true;
return color;
}
}
foundColor = false;
return color;
}
private void SetMaterialColorToDefault(Material mat, string[] colorProps, out bool foundColor)
{
foundColor = false;
for (int i = 0; i < colorProps.Length; i++)
{
if (mat.HasProperty(colorProps[i]))
{
Color currentColor = mat.GetColor(colorProps[i]);
if (currentColor != Color.white)
{
mat.SetColor(colorProps[i], Color.white);
}
foundColor = true;
}
}
}
private void SetMaterialTexture(Material mat, string[] albedoProps, Texture2D tex, out bool foundTexture)
{
foundTexture = false;
for (int i = 0; i < albedoProps.Length; i++)
{
if (mat.HasProperty(albedoProps[i]))
{
mat.SetTexture(albedoProps[i], tex);
foundTexture = true;
}
}
}
private Texture GetTextureFromMaterial(Material mat, string[] texProperties, out bool foundTex)
{
Texture tex = null;
for (int i = 0; i < texProperties.Length; i++)
{
string prop = texProperties[i];
if (mat.HasProperty(prop))
{
tex = mat.GetTexture(prop);
foundTex = true;
return tex;
}
}
foundTex = false;
return tex;
}
public static string BrowseOutputFolder()
{
string errorMsg;
bool success;
string path = EditorUtility.OpenFolderPanel("Browse for Output Folder", "", "");
path = MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(path, out errorMsg, out success);
if (success)
{
return path;
}
else
{
Debug.LogError(errorMsg);
return null;
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ddcca7684ef63bf4e99a0ecddc7a86ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_ColorTintTextureGenerator.cs
uploadId: 797180
@@ -0,0 +1,274 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2024 Ian Deane
//----------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEngine;
namespace DigitalOpus.MB.MBEditor
{
/// <summary>
/// Component that handles the UI for generating color tint textures for all materials in meshRenderers that belong to the texture baker.
///
/// The user is able to set a folder for textures to be generated to, set generated texture size, and add or remove color and albedo texture property names
/// that will be used when searching for materials that are candidates for color tint texture generation.
///
/// The user can see a list of all available materials under the texture baker and whether color tint textures will be generated for them or not.
/// Once the user is satisfied with this list they can generate color tint textures which will automatically be assigned to the relevant materials.
///
/// All the logic for this window is handled in the MB3_ColorTintTextureGenerator class.
/// </summary>
namespace DigitalOpus.MB.MBEditor
{
public class MB3_CreateColorTintWindow : EditorWindow
{
public MB3_TextureBaker textureBaker;
public MB3_TextureBaker newTextureBaker;
public string folderPath = "";
public int texSize = 16;
[SerializeField]
public string[] colorTintList = {
"_Color", //Built-in RP
"_BaseColor", //URP and HDRP
"_ColorTint", //Commonly Used
};
public SerializedObject colorTintWindowObject;
public SerializedProperty colorTintProperty;
[SerializeField]
public string[] albedoMapList = {
"_MainTex", //Built-in RP
"_BaseMap", // URP
"_BaseColorMap", //HDRP
};
public SerializedProperty albedoMapProperty;
private MB3_ColorTintTextureGenerator ctGen;
private bool doneGeneration = false;
private bool errorState;
private string errorMsg;
private List<MB3_ColorTintTextureGenerator.ColorTintTextureData> ctData;
private List<string> generatedFiles;
private Vector2 scrollPos;
private static GUIContent
gc_textureBakerSelect = new GUIContent("Texture Baker", "Choose texture baker. Solid color textures will be added to materials used by the \'Objects To Be Combined\'."),
gc_folderSelectHeader = new GUIContent("Select Folder for Saving Textures:", "Must be a valid folder in the Assets folder."),
gc_folderSelectButton = new GUIContent("Browse for Output Folder", "Must be a valid folder in the Assets folder."),
gc_colorPropertyNames = new GUIContent("Color Tint Property names",
"List of color tint property names that will be seached for in the source object materials."),
gc_albedoPropertyNames = new GUIContent("Albedo Map Property names",
"This is the list of texture property names that searched for in the source object materials. If this property is empty, it will be assigned a generated solid color texture."),
gc_texSizeField = new GUIContent("Set Texture Size in Pixels (must be power of two):", "The height/width size in pixels of the color tint textures that will be generated. This field must be a power of two."),
gc_findButton = new GUIContent("Find Color Tint Textures", "Search all materials used by 'Objects To Be Combined' for empty albedo texture properties and color tint properties. No assets will be modified. Results will be reported."),
gc_generateButton = new GUIContent("Generate Color Tint Textures", "Create new solid color textures and assign them to source materials. This will modify source material assets.");
[MenuItem("Window/Mesh Baker/Generate Color Tint Textures")]
public static void Open()
{
// open window
MB3_CreateColorTintWindow ctWin = (MB3_CreateColorTintWindow)EditorWindow.GetWindow(typeof(MB3_CreateColorTintWindow));
}
private void OnEnable()
{
colorTintWindowObject = new SerializedObject(this);
colorTintProperty = colorTintWindowObject.FindProperty("colorTintList");
albedoMapProperty = colorTintWindowObject.FindProperty("albedoMapList");
scrollPos = Vector2.zero;
errorState = false;
errorMsg = "";
ctData = null;
ctGen = null;
generatedFiles = new List<string>();
}
private void OnGUI()
{
//update serialized object
colorTintWindowObject.Update();
EditorGUILayout.HelpBox("This window finds materials used by the texture baker list of objects to be combined which have a color tint and no albedo texture. " +
"It will create solid color textures matching the color tint and assign them to the source material's albedo texture. \n\n" +
"Instructions:\n\n" +
"1. Select Texture Baker.\n\n" +
"2. Select folder where color tint textures will be saved.\n\n" +
"3. Add color tint property names or albedo map property names used by source materials.\n\n" +
"4. Set the output texture size. This must be a power of 2. The resulting texture will have height and width equal to \'size\'.\n\n" +
"5. Click \'Find Color Tint Textures\' to generate a dry-run report of affected materials and generated textures.\n\n" +
"6. Click \'Generate Color Tint Textures\' to generate solid color textures and assign them to source materials.", UnityEditor.MessageType.None);
newTextureBaker = (MB3_TextureBaker)EditorGUILayout.ObjectField(gc_textureBakerSelect, textureBaker, typeof(MB3_TextureBaker), true);
if (newTextureBaker != null &&
(newTextureBaker != textureBaker ||
ctGen == null))
{
textureBaker = newTextureBaker;
ctGen = new MB3_ColorTintTextureGenerator(textureBaker);
ctData = null;
}
// get folder to save textures in
EditorGUILayout.BeginHorizontal();
GUILayout.Label(gc_folderSelectHeader, EditorStyles.boldLabel);
if (GUILayout.Button(gc_folderSelectButton))
{
errorState = false;
folderPath = MB3_ColorTintTextureGenerator.BrowseOutputFolder();
if (folderPath == null)
{
errorState = true;
errorMsg = "Selected folder could not be found. Please select a different folder.";
}
}
EditorGUILayout.LabelField("Folder: " + folderPath);
EditorGUILayout.EndHorizontal();
// modifiable arrays for color and albedo property names
EditorGUILayout.PropertyField(colorTintProperty, gc_colorPropertyNames, true);
EditorGUILayout.PropertyField(albedoMapProperty, gc_albedoPropertyNames, true);
// set texture size field
EditorGUILayout.BeginHorizontal();
texSize = Mathf.ClosestPowerOfTwo(EditorGUILayout.IntField(gc_texSizeField, texSize));
EditorGUILayout.EndHorizontal();
if (texSize < 2)
{
texSize = 2;
}
// button for enumerating materials and whether or not they will be updated
if (GUILayout.Button(gc_findButton))
{
errorState = false;
if (ctGen == null)
{
errorState = true;
errorMsg = "Texture baker is not assigned. This operation requires a texture baker reference.";
}
else
{
try
{
generatedFiles.Clear();
ctData = ctGen.GenerateColorTintTextures(textureBaker, ctData, folderPath, texSize, colorTintList, albedoMapList, false, out generatedFiles);
doneGeneration = false;
}
catch (Exception e)
{
errorState = true;
Debug.LogError(e.Message);
errorMsg = e.Message;
}
}
}
// button to generate new color tint textures and update corresponding materials
if (GUILayout.Button(gc_generateButton))
{
errorState = false;
if (ctGen == null)
{
errorState = true;
errorMsg = "Texture baker is not set. This operation requires a texture baker reference.";
}
else
{
bool response = EditorUtility.DisplayDialog("Confirm Color Texture Generation",
"Are you sure you want to generate color tint textures?\nThis will modify materials used by the Objects To Be Combined.",
"Yes", "No");
if (response)
{
try
{
EditorUtility.DisplayProgressBar("Generate Color Tint Textures...", "", 0.5f);
ctGen.GenerateColorTintTextures(textureBaker, ctData, folderPath, texSize, colorTintList, albedoMapList, true, out generatedFiles);
doneGeneration = true;
}
catch (Exception e)
{
errorState = true;
Debug.LogError(e.Message);
errorMsg = e.Message;
}
finally
{
EditorUtility.ClearProgressBar();
}
}
}
}
scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, true);
{
if (errorState)
{
// if an error occurred during find or generate display it
GUIStyle errorStyle = new GUIStyle();
errorStyle.normal.textColor = Color.red;
EditorGUILayout.LabelField("Error: " + errorMsg, errorStyle);
}
else if (doneGeneration && generatedFiles != null && generatedFiles.Count > 0)
{
// display which new files were created
EditorGUILayout.LabelField("The following textures were generated in folder", EditorStyles.boldLabel);
EditorGUILayout.LabelField(folderPath, EditorStyles.boldLabel);
EditorGUILayout.Separator();
for (int i = 0; i < generatedFiles.Count; i++)
{
EditorGUILayout.LabelField(generatedFiles[i]);
}
}
else if (doneGeneration && (generatedFiles == null || generatedFiles.Count == 0))
{
// notify that no new textures were generated
EditorGUILayout.LabelField("No new texture files were generated.", EditorStyles.boldLabel);
}
else if (ctData != null && ctData.Count > 0)
{
// display data for each material detected our first pass through GenerateColorTintTextures
EditorGUILayout.LabelField("Detected Materials With Color Tints & Empty Albedo Properties:", EditorStyles.boldLabel);
for (int i = 0; i < ctData.Count; i++)
{
EditorGUILayout.Separator();
DisplayColorTintData(ctData[i]);
}
}
}
EditorGUILayout.EndScrollView();
colorTintWindowObject.ApplyModifiedProperties();
}
private void DisplayColorTintData(MB3_ColorTintTextureGenerator.ColorTintTextureData ctData)
{
StringBuilder sb = new StringBuilder();
if (ctData.willGenerateColorTexture)
{
// display information about color texture
sb.AppendLine("Material: " + ctData.mat + " Found color tint " + ctData.colorProperty + " Color tint texture will be generated.");
}
else
{
// explain why color tint texture will not be generated
if (ctData.mat != null)
{
sb.AppendLine("Material " + ctData.mat + " had the following issues:");
}
for (int i = 0; i < ctData.messages.Count; i++)
{
sb.AppendLine(ctData.messages[i]);
}
sb.AppendLine("Color tint texture will not be generated for this material.");
}
EditorGUILayout.LabelField(sb.ToString());
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: df558a29358f3c947920e07c881549c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_CreateColorTintWindow.cs
uploadId: 797180
@@ -0,0 +1,19 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_DisableHiddenAnimations))]
public class MB3_DisableHiddenAnimationsEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox(
"HOW TO USE \n\nPlace this component on the same game object that has the combined SkinMeshRenderer " +
"\n\n Drag game objects with Animator and/or Animation components that were baked into the combined SkinnedMeshRenderer into the lists below", MessageType.Info);
DrawDefaultInspector();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: e1435b73816486941b0ea827c7645cf6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_DisableHiddenAnimationsEditor.cs
uploadId: 797180
@@ -0,0 +1,567 @@
/**
* \brief Hax! DLLs cannot interpret preprocessor directives, so this class acts as a "bridge"
*/
using System;
using UnityEngine;
using UnityEditor;
using System.Collections;
using DigitalOpus.MB.Core;
using UnityEditor.Build;
namespace DigitalOpus.MB.Core
{
public class MBVersionEditorConcrete : MBVersionEditorInterface
{
/// <summary>
/// Used to map the activeBuildTarget to a string argument needed by TextureImporter.GetPlatformTextureSettings
/// The allowed values for GetPlatformTextureSettings are "Web", "Standalone", "iPhone", "Android" and "FlashPlayer".
/// </summary>
/// <returns></returns>
public string GetPlatformString()
{
#if (UNITY_4_6 || UNITY_4_7 || UNITY_4_5 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iPhone){
return "iPhone";
}
#else
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS)
{
return "iPhone";
}
#endif
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WSAPlayer)
{
return "Windows Store Apps";
}
#if (!UNITY_2018_3_OR_NEWER)
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.PSP2)
{
return "PSP2";
}
#endif
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.PS4)
{
return "PS4";
}
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.XboxOne)
{
return "XboxOne";
}
#if (UNITY_2017_3_OR_NEWER)
#else
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.SamsungTV)
{
return "Samsung TV";
}
#endif
#if (UNITY_5_5_OR_NEWER && !UNITY_2018_1_OR_NEWER)
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.N3DS)
{
return "Nintendo 3DS";
}
#endif
#if (UNITY_5_3 || UNITY_5_2 || UNITY_5_3_OR_NEWER)
#if (UNITY_2018_1_OR_NEWER)
// wiiu support was removed in 2018.1
#else
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WiiU)
{
return "WiiU";
}
#endif
#endif
#if (UNITY_5_3 || UNITY_5_3_OR_NEWER)
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.tvOS)
{
return "tvOS";
}
#endif
#if (UNITY_2018_2_OR_NEWER)
#else
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Tizen)
{
return "Tizen";
}
#endif
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android)
{
return "Android";
}
bool isLinuxStandalone = false;
#if UNITY_2019_2_OR_NEWER
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinux64)
{
isLinuxStandalone = true;
}
#else
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinux ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneLinuxUniversal)
{
isLinuxStandalone = true;
}
#endif
if (isLinuxStandalone ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneWindows64 ||
#if UNITY_2017_3_OR_NEWER
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSX
#else
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSXIntel ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSXIntel64 ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSXUniversal
#endif
)
{
return "Standalone";
}
#if !UNITY_5_4_OR_NEWER
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebPlayer ||
EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebPlayerStreamed
)
{
return "Web";
}
#endif
if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL)
{
return "WebGL";
}
return null;
}
public void RegisterUndo(UnityEngine.Object o, string s)
{
#if (UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
Undo.RegisterUndo(o, s);
#else
Undo.RecordObject(o, s);
#endif
}
public string GetScriptingDefineSymbolsFromTg(BuildTargetGroup tg)
{
#if UNITY_2021_2_OR_NEWER
NamedBuildTarget namedBuildTarget = NamedBuildTarget.FromBuildTargetGroup(tg);
return PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget);
#else
return PlayerSettings.GetScriptingDefineSymbolsForGroup(tg);
#endif
}
public void SetInspectorLabelWidth(float width)
{
#if (UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
EditorGUIUtility.LookLikeControls(width);
#else
EditorGUIUtility.labelWidth = width;
#endif
}
public void UpdateIfDirtyOrScript(SerializedObject so)
{
#if UNITY_5_6_OR_NEWER
so.UpdateIfRequiredOrScript();
#else
so.UpdateIfDirtyOrScript();
#endif
}
public bool GenerateSecondaryUVSetForUnwrapping(Mesh src, UnwrapParam settings)
{
#if UNITY_2022_1_OR_NEWER
bool unwrappingSuccessful = Unwrapping.GenerateSecondaryUVSet(src, settings);
return unwrappingSuccessful;
#else
Unwrapping.GenerateSecondaryUVSet(src, settings);
return true;
#endif
}
public UnityEngine.Object PrefabUtility_GetCorrespondingObjectFromSource(GameObject go)
{
#if UNITY_2018_2_OR_NEWER
return PrefabUtility.GetCorrespondingObjectFromSource(go);
#else
return PrefabUtility.GetPrefabParent(go);
#endif
}
public bool IsAutoPVRTC(TextureImporterFormat platformFormat, TextureImporterFormat platformDefaultFormat)
{
if ((
#if UNITY_2017_1_OR_NEWER
platformFormat == TextureImporterFormat.Automatic
#elif UNITY_5_5_OR_NEWER
platformFormat == TextureImporterFormat.Automatic ||
platformFormat == TextureImporterFormat.Automatic16bit ||
platformFormat == TextureImporterFormat.AutomaticCompressed ||
platformFormat == TextureImporterFormat.AutomaticCompressedHDR ||
platformFormat == TextureImporterFormat.AutomaticCrunched ||
platformFormat == TextureImporterFormat.AutomaticHDR
#else
platformFormat == TextureImporterFormat.Automatic16bit ||
platformFormat == TextureImporterFormat.AutomaticCompressed ||
platformFormat == TextureImporterFormat.AutomaticCrunched
#endif
) && (
platformDefaultFormat == TextureImporterFormat.PVRTC_RGB2 ||
platformDefaultFormat == TextureImporterFormat.PVRTC_RGB4 ||
platformDefaultFormat == TextureImporterFormat.PVRTC_RGBA2 ||
platformDefaultFormat == TextureImporterFormat.PVRTC_RGBA4
))
{
return true;
}
return false;
}
public MB_PrefabType PrefabUtility_GetPrefabType(UnityEngine.Object obj)
{
#if UNITY_2018_3_OR_NEWER
if (PrefabUtility.IsPartOfNonAssetPrefabInstance(obj))
{
return MB_PrefabType.scenePefabInstance;
}
if (!PrefabUtility.IsPartOfAnyPrefab(obj))
{
return MB_PrefabType.isInstanceAndNotAPartOfAnyPrefab;
}
PrefabAssetType assetType = PrefabUtility.GetPrefabAssetType(obj);
if (assetType == PrefabAssetType.NotAPrefab)
{
if (PrefabUtility.GetPrefabInstanceStatus(obj) != PrefabInstanceStatus.NotAPrefab)
{
return MB_PrefabType.isInstanceAndNotAPartOfAnyPrefab;
}
else
{
return MB_PrefabType.scenePefabInstance;
}
}
else if (assetType == PrefabAssetType.Model)
{
return MB_PrefabType.modelPrefabAsset;
}
else if (assetType == PrefabAssetType.Regular ||
assetType == PrefabAssetType.Variant ||
assetType == PrefabAssetType.MissingAsset)
{
return MB_PrefabType.prefabAsset;
}
else
{
Debug.Assert(false, "Should never get here. Unknown prefab asset type.");
return MB_PrefabType.isInstanceAndNotAPartOfAnyPrefab;
}
#else
PrefabType prefabType = PrefabUtility.GetPrefabType(obj);
if (prefabType == PrefabType.ModelPrefab)
{
return MB_PrefabType.modelPrefabAsset;
} else if (prefabType == PrefabType.Prefab)
{
return MB_PrefabType.prefabAsset;
} else if (prefabType == PrefabType.PrefabInstance || prefabType == PrefabType.ModelPrefabInstance)
{
return MB_PrefabType.scenePefabInstance;
} else
{
return MB_PrefabType.isInstanceAndNotAPartOfAnyPrefab;
}
#endif
}
public void PrefabUtility_UnpackPrefabInstance(UnityEngine.GameObject go, ref SerializedObject so)
{
#if UNITY_2018_3_OR_NEWER
UnityEngine.Object targetObj = null;
if (so != null) targetObj = so.targetObject;
PrefabUtility.UnpackPrefabInstance(go, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
// This is a workaround for a nasty Unity bug. The call to UnpackPrefabInstance
// corrupts the serialized object, Recreate a clean reference here.
if (so != null) so = new SerializedObject(targetObj);
#else
// Do nothing.
#endif
}
public void PrefabUtility_ReplacePrefab(GameObject gameObject, string assetPath, MB_ReplacePrefabOption replacePrefabOptions)
{
#if UNITY_2018_3_OR_NEWER
PrefabUtility.SaveAsPrefabAssetAndConnect(gameObject, assetPath, InteractionMode.AutomatedAction);
#else
GameObject obj = (GameObject) AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject));
PrefabUtility.ReplacePrefab(gameObject, obj, (ReplacePrefabOptions) replacePrefabOptions);
obj = (GameObject)AssetDatabase.LoadAssetAtPath(assetPath, typeof(GameObject));
if (replacePrefabOptions == MB_ReplacePrefabOption.nameBased)
{
PrefabUtility.ConnectGameObjectToPrefab(gameObject, obj);
}
#endif
}
public GameObject PrefabUtility_GetPrefabInstanceRoot(GameObject sceneInstance)
{
#if UNITY_2018_3_OR_NEWER
return PrefabUtility.GetOutermostPrefabInstanceRoot(sceneInstance);
#else
return PrefabUtility.FindRootGameObjectWithSameParentPrefab(sceneInstance);
#endif
}
public TextureImporterFormat Map_TextureFormat_2_TextureImporterFormat(TextureFormat texFormat, out bool success)
{
TextureImporterFormat texImporterFormat;
success = true;
switch (texFormat)
{
case TextureFormat.ARGB32:
texImporterFormat = TextureImporterFormat.ARGB32;
break;
case TextureFormat.RGBA32:
texImporterFormat = TextureImporterFormat.RGBA32;
break;
case TextureFormat.RGB24:
texImporterFormat = TextureImporterFormat.RGB24;
break;
case TextureFormat.Alpha8:
texImporterFormat = TextureImporterFormat.Alpha8;
break;
#if UNITY_2020_1_OR_NEWER
case TextureFormat.ASTC_10x10:
texImporterFormat = TextureImporterFormat.ASTC_10x10;
break;
case TextureFormat.ASTC_12x12:
texImporterFormat = TextureImporterFormat.ASTC_12x12;
break;
case TextureFormat.ASTC_4x4:
texImporterFormat = TextureImporterFormat.ASTC_4x4;
break;
case TextureFormat.ASTC_5x5:
texImporterFormat = TextureImporterFormat.ASTC_5x5;
break;
case TextureFormat.ASTC_6x6:
texImporterFormat = TextureImporterFormat.ASTC_6x6;
break;
case TextureFormat.ASTC_8x8:
texImporterFormat = TextureImporterFormat.ASTC_8x8;
break;
#else
case TextureFormat.ASTC_RGBA_10x10:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_10x10;
break;
case TextureFormat.ASTC_RGBA_12x12:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_12x12;
break;
case TextureFormat.ASTC_RGBA_4x4:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_4x4;
break;
case TextureFormat.ASTC_RGBA_5x5:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_5x5;
break;
case TextureFormat.ASTC_RGBA_6x6:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_6x6;
break;
case TextureFormat.ASTC_RGBA_8x8:
texImporterFormat = TextureImporterFormat.ASTC_RGBA_8x8;
break;
case TextureFormat.ASTC_RGB_10x10:
texImporterFormat = TextureImporterFormat.ASTC_RGB_10x10;
break;
case TextureFormat.ASTC_RGB_12x12:
texImporterFormat = TextureImporterFormat.ASTC_RGB_12x12;
break;
case TextureFormat.ASTC_RGB_4x4:
texImporterFormat = TextureImporterFormat.ASTC_RGB_4x4;
break;
case TextureFormat.ASTC_RGB_5x5:
texImporterFormat = TextureImporterFormat.ASTC_RGB_5x5;
break;
case TextureFormat.ASTC_RGB_6x6:
texImporterFormat = TextureImporterFormat.ASTC_RGB_6x6;
break;
case TextureFormat.ASTC_RGB_8x8:
texImporterFormat = TextureImporterFormat.ASTC_RGB_8x8;
break;
#endif
case TextureFormat.BC4:
texImporterFormat = TextureImporterFormat.BC4;
break;
case TextureFormat.BC5:
texImporterFormat = TextureImporterFormat.BC5;
break;
case TextureFormat.BC6H:
texImporterFormat = TextureImporterFormat.BC6H;
break;
case TextureFormat.BC7:
texImporterFormat = TextureImporterFormat.BC7;
break;
case TextureFormat.DXT1:
texImporterFormat = TextureImporterFormat.DXT1;
break;
case TextureFormat.DXT1Crunched:
texImporterFormat = TextureImporterFormat.DXT1Crunched;
break;
case TextureFormat.DXT5:
texImporterFormat = TextureImporterFormat.DXT5;
break;
case TextureFormat.DXT5Crunched:
texImporterFormat = TextureImporterFormat.DXT5Crunched;
break;
case TextureFormat.EAC_R:
texImporterFormat = TextureImporterFormat.EAC_R;
break;
case TextureFormat.EAC_RG:
texImporterFormat = TextureImporterFormat.EAC_RG;
break;
case TextureFormat.EAC_RG_SIGNED:
texImporterFormat = TextureImporterFormat.EAC_RG_SIGNED;
break;
case TextureFormat.EAC_R_SIGNED:
texImporterFormat = TextureImporterFormat.EAC_R_SIGNED;
break;
case TextureFormat.ETC_RGB4:
texImporterFormat = TextureImporterFormat.ETC_RGB4;
break;
#if UNITY_2017_3_OR_NEWER
case TextureFormat.ETC_RGB4Crunched:
texImporterFormat = TextureImporterFormat.ETC_RGB4Crunched;
break;
#endif
case TextureFormat.ETC2_RGB:
texImporterFormat = TextureImporterFormat.ETC2_RGB4;
break;
case TextureFormat.ETC2_RGBA8:
texImporterFormat = TextureImporterFormat.ETC2_RGBA8;
break;
#if UNITY_2017_3_OR_NEWER
case TextureFormat.ETC2_RGBA8Crunched:
texImporterFormat = TextureImporterFormat.ETC2_RGBA8Crunched;
break;
#endif
case TextureFormat.PVRTC_RGB2:
texImporterFormat = TextureImporterFormat.PVRTC_RGB2;
break;
case TextureFormat.PVRTC_RGB4:
texImporterFormat = TextureImporterFormat.PVRTC_RGB4;
break;
case TextureFormat.PVRTC_RGBA2:
texImporterFormat = TextureImporterFormat.PVRTC_RGBA2;
break;
case TextureFormat.PVRTC_RGBA4:
texImporterFormat = TextureImporterFormat.PVRTC_RGBA4;
break;
#if UNITY_2018_3_OR_NEWER
case TextureFormat.R16:
texImporterFormat = TextureImporterFormat.R16;
break;
#endif
#if UNITY_2018_2_OR_NEWER
case TextureFormat.R8:
texImporterFormat = TextureImporterFormat.R8;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RFloat:
texImporterFormat = TextureImporterFormat.RFloat;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RG16:
texImporterFormat = TextureImporterFormat.RG16;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RGB9e5Float:
texImporterFormat = TextureImporterFormat.RGB9E5;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RGHalf:
texImporterFormat = TextureImporterFormat.RGHalf;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RGFloat:
texImporterFormat = TextureImporterFormat.RGFloat;
break;
#endif
#if UNITY_2018_3_OR_NEWER
case TextureFormat.RHalf:
texImporterFormat = TextureImporterFormat.RHalf;
break;
#endif
default:
texImporterFormat = TextureImporterFormat.ARGB32;
success = false;
Debug.LogError("No mapping for TextureFormat: " + texFormat + " to a TextureImporterFormat. ");
break;
}
return texImporterFormat;
}
public void PrefabUtility_SavePrefabAsset(GameObject prefabAsset)
{
#if UNITY_2018_3_OR_NEWER
PrefabUtility.SavePrefabAsset(prefabAsset);
#endif
}
public void PrefabUtility_ApplyPrefabInstance(GameObject instance)
{
#if UNITY_2018_3_OR_NEWER
PrefabUtility.ApplyPrefabInstance(instance, InteractionMode.AutomatedAction);
#else
PropertyModification[] mods = PrefabUtility.GetPropertyModifications(instance);
PrefabUtility.SetPropertyModifications(instance, mods);
#endif
}
public GameObject PrefabUtility_CreatePrefab(string path, GameObject go)
{
#if UNITY_2018_3_OR_NEWER
return PrefabUtility.SaveAsPrefabAsset(go, path);
#else
return PrefabUtility.CreatePrefab(path, go);
#endif
}
public GameObject PrefabUtility_FindPrefabRoot(GameObject sourceObj)
{
#if UNITY_2018_3_OR_NEWER
if (sourceObj == null) return null;
if (MB_Utility.IsSceneInstance(sourceObj))
{
return PrefabUtility.GetOutermostPrefabInstanceRoot(sourceObj);
} else
{
return sourceObj.transform.root.gameObject;
}
#else
return PrefabUtility.FindPrefabRoot(sourceObj);
#endif
}
public GameObject GetCorrespondingObjectFromSource(GameObject sourceObj)
{
#if UNITY_2018_3_OR_NEWER
return PrefabUtility.GetCorrespondingObjectFromSource(sourceObj);
#else
return (GameObject) PrefabUtility.GetPrefabParent(sourceObj);
#endif
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 86e7cea5d902c1647b14db77b02f967e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MBVersionConcreteEditor.cs
uploadId: 797180
@@ -0,0 +1,104 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
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;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_MeshBaker))]
[CanEditMultipleObjects]
public class MB3_MeshBakerEditor : Editor
{
MB3_MeshBakerEditorInternal mbe = new MB3_MeshBakerEditorInternal();
[MenuItem("GameObject/Create Other/Mesh Baker/TextureBaker and MeshBaker", false, 100)]
public static GameObject CreateNewMeshBaker()
{
MB3_TextureBaker[] mbs = (MB3_TextureBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_TextureBaker));
Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
int largest = 0;
try
{
for (int i = 0; i < mbs.Length; i++)
{
Match match = regex.Match(mbs[i].name);
if (match.Success)
{
int val = Convert.ToInt32(match.Groups[1].Value);
if (val >= largest)
largest = val + 1;
}
}
}
catch (Exception e)
{
if (e == null) e = null; //Do nothing supress compiler warning
}
GameObject nmb = new GameObject("TextureBaker (" + largest + ")");
nmb.transform.position = Vector3.zero;
MB3_TextureBaker tb = nmb.AddComponent<MB3_TextureBaker>();
tb.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
MB3_MeshBakerGrouper mbg = nmb.AddComponent<MB3_MeshBakerGrouper>();
GameObject meshBaker = new GameObject("MeshBaker");
MB3_MeshBaker mb = meshBaker.AddComponent<MB3_MeshBaker>();
meshBaker.transform.parent = nmb.transform;
mb.meshCombiner.settingsHolder = mbg;
return nmb.gameObject;
}
[MenuItem("GameObject/Create Other/Mesh Baker/MeshBaker", false, 100)]
public static GameObject CreateNewMeshBakerOnly()
{
MB3_MeshBaker[] mbs = (MB3_MeshBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_MeshBaker));
Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
int largest = 0;
try
{
for (int i = 0; i < mbs.Length; i++)
{
Match match = regex.Match(mbs[i].name);
if (match.Success)
{
int val = Convert.ToInt32(match.Groups[1].Value);
if (val >= largest)
largest = val + 1;
}
}
}
catch (Exception e)
{
if (e == null) e = null; //Do nothing supress compiler warning
}
GameObject meshBaker = new GameObject("MeshBaker (" + largest + ")");
meshBaker.AddComponent<MB3_MeshBaker>();
return meshBaker.gameObject;
}
void OnEnable()
{
mbe.OnEnable(serializedObject);
}
void OnDisable()
{
mbe.OnDisable();
}
public override void OnInspectorGUI()
{
mbe.OnInspectorGUI(serializedObject, (MB3_MeshBakerCommon)target, targets, typeof(MB3_MeshBakerEditorWindow));
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: d0de7b6551ddaeb4091cb0d096f8963b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditor.cs
uploadId: 797180
@@ -0,0 +1,370 @@
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;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d79478bd8098cb741ba334439ac504b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditorFunctions.cs
uploadId: 797180
@@ -0,0 +1,712 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
using UnityEditor;
namespace DigitalOpus.MB.MBEditor
{
public interface MB3_MeshBakerEditorWindowInterface
{
MonoBehaviour target
{
get;
set;
}
}
public class MB_EditorStyles
{
public GUIStyle multipleMaterialBackgroundStyle = new GUIStyle();
public GUIStyle multipleMaterialBackgroundStyleDarker = new GUIStyle();
public GUIStyle editorBoxBackgroundStyle = new GUIStyle();
Texture2D multipleMaterialBackgroundColor;
Texture2D multipleMaterialBackgroundColorDarker;
Texture2D editorBoxBackgroundColor;
public void Init()
{
bool isPro = EditorGUIUtility.isProSkin;
Color backgroundColor = isPro
? new Color32(35, 35, 35, 255)
: new Color32(174, 174, 174, 255);
if (multipleMaterialBackgroundColor == null)
{
multipleMaterialBackgroundColor = MB3_MeshBakerEditorFunctions.MakeTex(8, 8, backgroundColor);
}
backgroundColor = isPro
? new Color32(50, 50, 50, 255)
: new Color32(160, 160, 160, 255);
if (multipleMaterialBackgroundColorDarker == null)
{
multipleMaterialBackgroundColorDarker = MB3_MeshBakerEditorFunctions.MakeTex(8, 8, backgroundColor);
}
backgroundColor = isPro
? new Color32(35, 35, 35, 255)
: new Color32(174, 174, 174, 255);
multipleMaterialBackgroundStyle.normal.background = multipleMaterialBackgroundColor;
multipleMaterialBackgroundStyleDarker.normal.background = multipleMaterialBackgroundColorDarker;
if (editorBoxBackgroundColor == null)
{
editorBoxBackgroundColor = MB3_MeshBakerEditorFunctions.MakeTex(8, 8, backgroundColor);
}
editorBoxBackgroundStyle.normal.background = editorBoxBackgroundColor;
editorBoxBackgroundStyle.border = new RectOffset(0, 0, 0, 0);
editorBoxBackgroundStyle.margin = new RectOffset(5, 5, 5, 5);
editorBoxBackgroundStyle.padding = new RectOffset(10, 10, 10, 10);
}
public void DestroyTextures()
{
if (multipleMaterialBackgroundColor != null) GameObject.DestroyImmediate(multipleMaterialBackgroundColor);
if (multipleMaterialBackgroundColorDarker != null) GameObject.DestroyImmediate(multipleMaterialBackgroundColorDarker);
if (editorBoxBackgroundColor != null) GameObject.DestroyImmediate(editorBoxBackgroundColor);
}
}
public class MB3_MeshBakerEditorInternal
{
//add option to exclude skinned mesh renderer and mesh renderer in filter
//example scenes for multi material
private static GUIContent
gc_outputOptoinsGUIContent = new GUIContent("Output"),
gc_logLevelContent = new GUIContent("Log Level"),
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."),
gc_parentSceneObject = new GUIContent("Parent Scene Object (Optional)", "Must be a scene object. If set, then combined meshes will be added as children of this GameObject in the hierarchy."),
gc_resultPrefabLeaveInstanceInSceneAfterBake = new GUIContent("Leave Instance In Scene After Bake", "If checked, then an instance will be left in the scene after baking. Otherwise scene instance will be deleted after prefab is baked."),
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"),
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."),
gc_useTextureBakerObjsGUIContent = new GUIContent("Same As Texture Baker", "Build a combined mesh using the same list of objects that generated the Combined Material"),
gc_combinedMeshPrefabGUIContent = new GUIContent("Combined Mesh Prefab", "Create a new prefab asset and drag an empty game object to it. Drag the prefab asset here."),
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."),
gc_combinedMesh = new GUIContent("Mesh", "This is the Mesh used by this MeshBaker and assigned to the combined Renderer.\n\n" +
"If it is null, then a new Mesh will be created for the next bake.\n\n" +
"If it is a project folder asset, then that asset will be overwitten (changes may be reverted if the scene is not saved).\n\n" +
"If you are re-using the same MeshBaker to bake different combined meshes, set this to null before each new bake. If you don't, then each bake will overwrite the previous bake's mesh."),
gc_saveMeshAsAsset = new GUIContent("Save Mesh", "Saves the mesh as an asset in the Project folder. " +
"If this button is enabled, then the mesh only exists in this scene. " +
"It cannot be used in other scenes. "),
gc_Settings = new GUIContent("Use Shared Settings", "Different MeshBakers can share the same settings. If this field is None, then the settings below will be used. " +
"Assign one of the following:\n" +
" - Mesh Baker Settings project asset \n" +
" - Mesh Baker Grouper scene instance \n");
private SerializedObject meshBaker;
private SerializedProperty logLevel, combiner, outputOptions, textureBakeResults, useObjsToMeshFromTexBaker, objsToMesh, mesh, sortOrderAxis, parentSceneObject, resultPrefabLeaveInstanceInSceneAfterBake;
private SerializedProperty settingsHolder;
private MB_MeshBakerSettingsEditor meshBakerSettingsThis;
private MB_MeshBakerSettingsEditor meshBakerSettingsExternal;
bool showInstructions = false;
bool showContainsReport = true;
private int objsToBeCombined_CurrentPage = 1;
private int objsToBecombined_NumPerPage = 50;
MB_EditorStyles editorStyles = new MB_EditorStyles();
Color buttonColor = new Color(.8f, .8f, 1f, 1f);
void _init(SerializedObject mb)
{
this.meshBaker = mb;
objsToMesh = meshBaker.FindProperty("objsToMesh");
combiner = meshBaker.FindProperty("_meshCombiner");
parentSceneObject = meshBaker.FindProperty("parentSceneObject");
resultPrefabLeaveInstanceInSceneAfterBake = meshBaker.FindProperty("resultPrefabLeaveInstanceInSceneAfterBake");
logLevel = combiner.FindPropertyRelative("_LOG_LEVEL");
outputOptions = combiner.FindPropertyRelative("_outputOption");
useObjsToMeshFromTexBaker = meshBaker.FindProperty("useObjsToMeshFromTexBaker");
textureBakeResults = combiner.FindPropertyRelative("_textureBakeResults");
mesh = combiner.FindPropertyRelative("_mesh");
sortOrderAxis = meshBaker.FindProperty("sortAxis");
settingsHolder = combiner.FindPropertyRelative("_settingsHolder");
meshBakerSettingsThis = new MB_MeshBakerSettingsEditor();
meshBakerSettingsThis.OnEnable(combiner);
editorStyles.Init();
}
public void OnEnable(SerializedObject meshBaker)
{
_init(meshBaker);
}
public void OnDisable()
{
editorStyles.DestroyTextures();
if (meshBakerSettingsThis != null) meshBakerSettingsThis.OnDisable();
if (meshBakerSettingsExternal != null) meshBakerSettingsExternal.OnDisable();
}
public void OnInspectorGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, UnityEngine.Object[] targets, System.Type editorWindowType)
{
target.UpgradeToCurrentVersionIfNecessary();
DrawGUI(meshBaker, target, targets, editorWindowType);
}
public void DrawGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, UnityEngine.Object[] targets, System.Type editorWindowType)
{
if (meshBaker == null)
{
return;
}
meshBaker.Update();
showInstructions = EditorGUILayout.Foldout(showInstructions, "Instructions:");
if (showInstructions)
{
EditorGUILayout.HelpBox("1. Bake combined material(s).\n\n" +
"2. If necessary set the 'Texture Bake Results' field.\n\n" +
"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" +
"4. Select options and 'Bake'.\n\n" +
"5. Look at warnings/errors in console. Decide if action needs to be taken.\n\n" +
"6. (optional) Disable renderers in source objects.", UnityEditor.MessageType.None);
EditorGUILayout.Separator();
}
MB3_MeshBakerCommon momm = (MB3_MeshBakerCommon)target;
EditorGUILayout.PropertyField(logLevel, gc_logLevelContent);
EditorGUILayout.PropertyField(textureBakeResults, gc_textureBakeResultsGUIContent);
bool doingTextureArray = false;
if (textureBakeResults.objectReferenceValue != null)
{
doingTextureArray = ((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).resultType == MB2_TextureBakeResults.ResultType.textureArray;
showContainsReport = EditorGUILayout.Foldout(showContainsReport, "Shaders & Materials Contained");
if (showContainsReport)
{
EditorGUILayout.HelpBox(((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).GetDescription(), MessageType.Info);
}
}
EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
EditorGUILayout.LabelField("Objects To Be Combined", EditorStyles.boldLabel);
if (momm.GetTextureBaker() != null)
{
EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
}
else
{
useObjsToMeshFromTexBaker.boolValue = false;
momm.useObjsToMeshFromTexBaker = false;
GUI.enabled = false;
EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
GUI.enabled = true;
}
if (!momm.useObjsToMeshFromTexBaker)
{
if (GUILayout.Button(gc_openToolsWindowLabelContent))
{
MB3_MeshBakerEditorWindow mmWin = (MB3_MeshBakerEditorWindow) EditorWindow.GetWindow(editorWindowType);
mmWin.SetTarget((MB3_MeshBakerRoot)momm);
}
object[] objs = MB3_EditorMethods.DropZone("Drag & Drop Renderers or Parents\n" + "HERE\n" +
"to add objects to be combined", 300, 50);
MB3_EditorMethods.AddDroppedObjects(objs, momm.GetObjectsToCombine());
MB_PaginatedList.GenerateObjectsToBeCombinedList(objsToMesh, ref objsToBeCombined_CurrentPage, ref objsToBecombined_NumPerPage);
EditorGUILayout.Separator();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select Objects In Scene"))
{
List<MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
List<GameObject> obsToCombine = new List<GameObject>();
foreach(MB3_MeshBakerCommon baker in selectedBakers) obsToCombine.AddRange(baker.GetObjectsToCombine());
Selection.objects = obsToCombine.ToArray();
if (momm.GetObjectsToCombine().Count > 0)
{
SceneView.lastActiveSceneView.pivot = momm.GetObjectsToCombine()[0].transform.position;
}
}
if (GUILayout.Button(gc_SortAlongAxis))
{
MB3_MeshBakerRoot.ZSortObjects sorter = new MB3_MeshBakerRoot.ZSortObjects();
sorter.sortAxis = sortOrderAxis.vector3Value;
sorter.SortByDistanceAlongAxis(momm.GetObjectsToCombine());
}
EditorGUILayout.PropertyField(sortOrderAxis, GUIContent.none);
EditorGUILayout.EndHorizontal();
}
else
{
GUI.enabled = false;
EditorGUILayout.PropertyField(objsToMesh, gc_objectsToCombineGUIContent, true);
GUI.enabled = true;
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(outputOptions, gc_outputOptoinsGUIContent);
if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject)
{
EditorGUI.BeginChangeCheck();
Transform pgo = (Transform)EditorGUILayout.ObjectField(gc_parentSceneObject, parentSceneObject.objectReferenceValue, typeof(Transform), true);
if (EditorGUI.EndChangeCheck())
{
if (pgo != null && MB_Utility.IsSceneInstance(pgo.gameObject))
{
parentSceneObject.objectReferenceValue = pgo;
}
else
{
parentSceneObject.objectReferenceValue = null;
}
}
//todo switch to renderer
momm.meshCombiner.resultSceneObject = (GameObject)EditorGUILayout.ObjectField("Combined Mesh Object", momm.meshCombiner.resultSceneObject, typeof(GameObject), true);
if (momm is MB3_MeshBaker)
{
EditorGUILayout.BeginHorizontal();
string l = "Mesh";
Mesh m = (Mesh)mesh.objectReferenceValue;
if (m != null)
{
l += " (" + m.GetInstanceID() + ")";
}
Mesh nm = (Mesh)EditorGUILayout.ObjectField(gc_combinedMesh, m, typeof(Mesh), true);
if (nm != m)
{
Undo.RecordObject(momm, "Assign Mesh");
MB3_MeshCombinerSingle.MeshCreationConditions meshBirthType = ((MB3_MeshCombinerSingle)momm.meshCombiner).SetMesh(nm);
SerializedProperty meshBirth = combiner.FindPropertyRelative("_meshBirth"); // SetMesh sets the _meshBirth field but it doesn't get remembered unless we do this.
meshBirth.enumValueIndex = (int)meshBirthType;
mesh.objectReferenceValue = nm;
}
if (!MB3_MeshCombinerSingle.EVAL_VERSION)
{
bool enableSaveMeshButton = _ShouldWeEnableSaveAsAsset(target);
{
EditorGUI.BeginDisabledGroup(!enableSaveMeshButton);
if (GUILayout.Button(gc_saveMeshAsAsset))
{
_SaveMeshAsAsset(target);
}
EditorGUI.EndDisabledGroup();
}
}
EditorGUILayout.EndHorizontal();
}
}
else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab)
{
if (momm.meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer)
{
EditorGUILayout.HelpBox("The workflow for baking Skinned Meshes into prefabs has changed as of version 29.1. " +
"It is no longer necessary to manually copy bones to the target prefab after baking. This should happen automatically.", MessageType.Info);
}
EditorGUI.BeginChangeCheck();
Transform pgo = (Transform)EditorGUILayout.ObjectField(gc_parentSceneObject, parentSceneObject.objectReferenceValue, typeof(Transform), true);
if (EditorGUI.EndChangeCheck())
{
if (pgo != null && MB_Utility.IsSceneInstance(pgo.gameObject))
{
parentSceneObject.objectReferenceValue = pgo;
}
else
{
parentSceneObject.objectReferenceValue = null;
}
}
EditorGUILayout.BeginHorizontal();
momm.resultPrefab = (GameObject)EditorGUILayout.ObjectField(gc_combinedMeshPrefabGUIContent, momm.resultPrefab, typeof(GameObject), true);
if (momm.resultPrefab != null)
{
string assetPath = AssetDatabase.GetAssetPath(momm.resultPrefab);
if (assetPath == null || assetPath.Length == 0)
{
Debug.LogError("The " + gc_combinedMeshPrefabGUIContent.text + " must be a prefab asset, not a scene GameObject");
momm.resultPrefab = null;
}
else
{
MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(momm.resultPrefab);
if (pt != MB_PrefabType.prefabAsset)
{
Debug.LogError("The " + gc_combinedMeshPrefabGUIContent.text + " must be a prefab asset, the prefab type was '" + pt + "'");
momm.resultPrefab = null;
}
}
}
else
{
if (GUILayout.Button("Create Empty Prefab"))
{
if (!Application.isPlaying)
{
string path = EditorUtility.SaveFilePanelInProject("Create Empty Prefab", "MyPrefab", "prefab", "Create a prefab containing an empty GameObject");
string pathNoFolder = Path.GetDirectoryName(path);
string fileNameNoExt = Path.GetFileNameWithoutExtension(path);
List<MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
if (selectedBakers.Count > 1) Debug.Log("About to create prefabs for " + selectedBakers.Count);
int idx = 0;
foreach (MB3_MeshBakerCommon baker in selectedBakers)
{
createEmptyPrefab(baker, pathNoFolder, fileNameNoExt, idx);
idx++;
}
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(resultPrefabLeaveInstanceInSceneAfterBake, gc_resultPrefabLeaveInstanceInSceneAfterBake);
if (momm is MB3_MeshBaker)
{
string l = "Mesh";
Mesh m = (Mesh)mesh.objectReferenceValue;
if (m != null)
{
l += " (" + m.GetInstanceID() + ")";
}
Mesh nm = (Mesh)EditorGUILayout.ObjectField(gc_combinedMesh, m, typeof(Mesh), true);
if (nm != m)
{
Undo.RecordObject(momm, "Assign Mesh");
((MB3_MeshCombinerSingle)momm.meshCombiner).SetMesh(nm);
mesh.objectReferenceValue = nm;
}
}
}
else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeMeshAssetsInPlace)
{
EditorGUILayout.HelpBox("Try the BatchPrefabBaker component! It makes preparing a batch of prefabs for static/ dynamic batching much easier.", MessageType.Info);
if (GUILayout.Button("Choose Folder For Bake In Place Meshes"))
{
string newFolder = EditorUtility.SaveFolderPanel("Folder For Bake In Place Meshes", Application.dataPath, "");
if (!newFolder.Contains(Application.dataPath)) Debug.LogWarning("The chosen folder must be in your assets folder.");
string folder = "Assets" + newFolder.Replace(Application.dataPath, "");
List<MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
Undo.RecordObjects(targets, "Undo Set Folder");
foreach (MB3_MeshBakerCommon baker in selectedBakers)
{
baker.bakeAssetsInPlaceFolderPath = folder;
EditorUtility.SetDirty(baker);
}
}
EditorGUILayout.LabelField("Folder For Meshes: " + momm.bakeAssetsInPlaceFolderPath);
}
if (momm is MB3_MultiMeshBaker)
{
MB3_MultiMeshCombiner mmc = (MB3_MultiMeshCombiner)momm.meshCombiner;
mmc.maxVertsInMesh = EditorGUILayout.IntField("Max Verts In Mesh", mmc.maxVertsInMesh);
}
//-----------------------------------
EditorGUILayout.Space();
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
bool settingsEnabled = true;
//------------- Mesh Baker Settings is a bit tricky because it is an interface.
EditorGUILayout.Space();
UnityEngine.Object obj = settingsHolder.objectReferenceValue;
// Don't use a PropertyField because we may not be able to use the assigned object. It may not implement requried interface.
obj = EditorGUILayout.ObjectField(gc_Settings, obj, typeof(UnityEngine.Object), true);
if (obj == null)
{
settingsEnabled = true;
settingsHolder.objectReferenceValue = null;
if (meshBakerSettingsExternal != null)
{
meshBakerSettingsExternal.OnDisable();
meshBakerSettingsExternal = null;
}
}
else if (obj is GameObject)
{
// Check to see if there is a component on this game object that implements MB_IMeshBakerSettingsHolder
MB_IMeshBakerSettingsHolder itf = (MB_IMeshBakerSettingsHolder)((GameObject)obj).GetComponent(typeof(MB_IMeshBakerSettingsHolder));
if (itf != null)
{
settingsEnabled = false;
Component settingsHolderComponent = (Component)itf;
if (settingsHolder.objectReferenceValue != settingsHolderComponent)
{
settingsHolder.objectReferenceValue = settingsHolderComponent;
meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
UnityEngine.Object targetObj;
string propertyName;
itf.GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
meshBakerSettingsExternal.OnEnable(meshBakerSettings);
}
}
else
{
Debug.LogError("You must drag a MeshBakerGrouper or a MeshCombinerSetting asset to this field.");
settingsEnabled = true;
settingsHolder.objectReferenceValue = null;
if (meshBakerSettingsExternal != null)
{
meshBakerSettingsExternal.OnDisable();
meshBakerSettingsExternal = null;
}
}
}
else if (obj is MB_IMeshBakerSettingsHolder)
{
settingsEnabled = false;
if (settingsHolder.objectReferenceValue != obj)
{
settingsHolder.objectReferenceValue = obj;
meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
UnityEngine.Object targetObj;
string propertyName;
((MB_IMeshBakerSettingsHolder)obj).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
meshBakerSettingsExternal.OnEnable(meshBakerSettings);
}
}
else
{
Debug.LogError("You must drag a MeshBakerGrouper or a MeshCombinerSetting asset to this field.");
}
EditorGUILayout.Space();
if (settingsHolder.objectReferenceValue == null)
{
// Use the meshCombiner settings
meshBakerSettingsThis.DrawGUI(momm.meshCombiner, settingsEnabled, doingTextureArray);
}
else
{
if (meshBakerSettingsExternal == null)
{
meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
UnityEngine.Object targetObj;
string propertyName;
((MB_IMeshBakerSettingsHolder)obj).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
meshBakerSettingsExternal.OnEnable(meshBakerSettings);
}
meshBakerSettingsExternal.DrawGUI(((MB_IMeshBakerSettingsHolder)settingsHolder.objectReferenceValue).GetMeshBakerSettings(), settingsEnabled, doingTextureArray);
}
Color oldColor = GUI.backgroundColor;
GUI.backgroundColor = buttonColor;
if (GUILayout.Button("Bake"))
{
List<MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
if (selectedBakers.Count > 1) Debug.Log("About to bake " + selectedBakers.Count);
foreach(MB3_MeshBakerCommon baker in selectedBakers)
{
// Why are we caching and recreating the SerializedObject? Because "bakeIntoPrefab" corrupts the serialized object
// and the meshBaker SerializedObject throws an NRE the next time it gets used.
MB3_MeshBakerCommon mbr = (MB3_MeshBakerCommon) meshBaker.targetObject;
bake(baker);
meshBaker = new SerializedObject(mbr);
}
}
GUI.backgroundColor = oldColor;
string enableRenderersLabel;
bool disableRendererInSource = false;
if (momm.GetObjectsToCombine().Count > 0)
{
Renderer r = MB_Utility.GetRenderer(momm.GetObjectsToCombine()[0]);
if (r != null && r.enabled) disableRendererInSource = true;
}
if (disableRendererInSource)
{
enableRenderersLabel = "Disable Renderers On Source Objects";
}
else
{
enableRenderersLabel = "Enable Renderers On Source Objects";
}
if (GUILayout.Button(enableRenderersLabel))
{
List<MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
foreach (MB3_MeshBakerCommon baker in selectedBakers)
{
baker.EnableDisableSourceObjectRenderers(!disableRendererInSource);
}
}
meshBaker.ApplyModifiedProperties();
meshBaker.SetIsDifferentCacheDirty();
}
public static void updateProgressBar(string msg, float progress)
{
EditorUtility.DisplayProgressBar("Combining Meshes", msg, progress);
}
public static bool bake(MB3_MeshBakerCommon mom)
{
SerializedObject so = null;
return bake(mom, ref so);
}
private List<MB3_MeshBakerCommon> _getBakersFromTargets(UnityEngine.Object[] targs)
{
List<MB3_MeshBakerCommon> outList = new List<MB3_MeshBakerCommon>(targs.Length);
for (int i = 0; i < targs.Length; i++)
{
outList.Add((MB3_MeshBakerCommon) targs[i]);
}
return outList;
}
private bool _ShouldWeEnableSaveAsAsset(MB3_MeshBakerCommon target)
{
if (!(target is MB3_MeshBaker))
{
return false;
}
MB3_MeshBaker mb = (MB3_MeshBaker) target;
Mesh bakedMesh = ((MB3_MeshCombinerSingle)mb.meshCombiner).GetMesh();
bool meshIsNull = bakedMesh == null;
bool meshHasNoVertices = bakedMesh.vertexCount == 0;
bool meshIsAlreadyAnAsset = !string.IsNullOrEmpty(AssetDatabase.GetAssetPath(bakedMesh));
bool disableSaveMeshButton = meshIsNull || meshHasNoVertices || meshIsAlreadyAnAsset;
return !disableSaveMeshButton;
}
private void _SaveMeshAsAsset(MB3_MeshBakerCommon target)
{
if (!(target is MB3_MeshBaker))
{
return;
}
MB3_MeshBaker mb = (MB3_MeshBaker)target;
Mesh bakedMesh = ((MB3_MeshCombinerSingle)mb.meshCombiner).GetMesh();
string path = EditorUtility.SaveFilePanel("Save Mesh", "Assets", "myMesh", "asset");
if (string.IsNullOrEmpty(path))
{
Debug.Log("No path selected.");
return;
}
string projectPath = Application.dataPath;
if (path.StartsWith(projectPath) == false)
{
Debug.Log("Path must be inside of the Assets folder.");
return;
}
Mesh meshAsset = MB3_MeshBakerEditorFunctionsCore.SaveMeshAsAsset(bakedMesh, path);
((MB3_MeshCombinerSingle)mb.meshCombiner).SetMesh(meshAsset);
}
private static void createEmptyPrefab(MB3_MeshBakerCommon mom, string folder, string prefabNameNoExtension, int idx)
{
if (prefabNameNoExtension != null && prefabNameNoExtension.Length > 0)
{
string prefabName = prefabNameNoExtension + idx;
GameObject go = new GameObject(prefabName);
string fullName = folder + "/" + prefabName + ".prefab";
fullName = AssetDatabase.GenerateUniqueAssetPath(fullName);
Debug.Log(fullName);
MBVersionEditor.PrefabUtility_CreatePrefab(fullName, go);
GameObject.DestroyImmediate(go);
SerializedObject so = new SerializedObject(mom);
so.FindProperty("resultPrefab").objectReferenceValue = (GameObject)AssetDatabase.LoadAssetAtPath(fullName, typeof(GameObject));
so.ApplyModifiedProperties();
}
}
/// <summary>
/// Bakes a combined mesh.
/// </summary>
/// <param name="mom"></param>
/// <param name="so">This is needed to work around a Unity bug where UnpackPrefabInstance corrupts
/// a SerializedObject. Only needed for bake into prefab.</param>
public static bool bake(MB3_MeshBakerCommon mom, ref SerializedObject so)
{
bool createdDummyTextureBakeResults = false;
bool success = false;
try
{
if (mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject ||
mom.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab)
{
success = MB3_MeshBakerEditorFunctions.BakeIntoCombined(mom, out createdDummyTextureBakeResults, ref so);
}
else
{
//bake meshes in place
if (mom is MB3_MeshBaker)
{
if (MB3_MeshCombiner.EVAL_VERSION)
{
Debug.LogError("Bake Mesh Assets In Place is disabled in the evaluation version.");
}
else
{
MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.prefabOnly, new MB3_EditorMethods(), vl)) return false;
List<GameObject> objsToMesh = mom.GetObjectsToCombine();
success = MB3_BakeInPlace.BakeMeshesInPlace((MB3_MeshCombinerSingle)((MB3_MeshBaker)mom).meshCombiner, objsToMesh, mom.bakeAssetsInPlaceFolderPath, mom.meshCombiner.clearBuffersAfterBake, updateProgressBar);
}
}
else
{
Debug.LogError("Multi Mesh Baker components cannot be used for Bake Mesh Assets In Place. Use an ordinary MeshBaker object instead.");
}
}
mom.meshCombiner.CheckIntegrity();
}
catch (Exception ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
}
finally
{
if (createdDummyTextureBakeResults && mom.textureBakeResults != null)
{
MB_Utility.Destroy(mom.textureBakeResults);
mom.textureBakeResults = null;
}
mom.meshCombiner.Dispose();
EditorUtility.ClearProgressBar();
}
return success;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 6187499e1f9c67c4b8f295a0d54cb7ba
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditorInternal.cs
uploadId: 797180
@@ -0,0 +1,64 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_MeshBakerEditorWindow : EditorWindow
{
MB3_MeshBakerEditorWindowAddObjectsTab addObjectsTab;
MB3_MeshBakerEditorWindowAnalyseSceneTab analyseSceneTab;
Vector2 scrollPos = Vector2.zero;
int selectedTab = 0;
GUIContent[] tabs = new GUIContent[] { new GUIContent("Analyse Scene & Generate Bakers"), new GUIContent("Search For Meshes To Add") };
[MenuItem("Window/Mesh Baker/Mesh Baker")]
static void Init()
{
EditorWindow.GetWindow(typeof(MB3_MeshBakerEditorWindow));
}
public void SetTarget(MB3_MeshBakerRoot targ)
{
if (addObjectsTab == null) addObjectsTab = new MB3_MeshBakerEditorWindowAddObjectsTab();
addObjectsTab.target = targ;
}
void OnGUI()
{
selectedTab = GUILayout.Toolbar(selectedTab, tabs);
scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(position.width), GUILayout.Height(position.height));
if (selectedTab == 0)
{
analyseSceneTab.drawTabAnalyseScene(position);
}
else
{
addObjectsTab.drawTabAddObjectsToBakers();
}
EditorGUILayout.EndScrollView();
}
void OnEnable()
{
if (addObjectsTab == null) addObjectsTab = new MB3_MeshBakerEditorWindowAddObjectsTab();
if (analyseSceneTab == null) analyseSceneTab = new MB3_MeshBakerEditorWindowAnalyseSceneTab();
addObjectsTab.OnEnable();
}
void OnDisable()
{
addObjectsTab.OnDisable();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 08905a0f08b77054d9ee3ee91b6a3804
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditorWindow.cs
uploadId: 797180
@@ -0,0 +1,836 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using DigitalOpus.MB.Core;
using UnityEngine.Rendering;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_MeshBakerEditorWindowAddObjectsTab : MB3_MeshBakerEditorWindowInterface
{
public enum OpacityType
{
unknown = -1,
opaque = 0,
transparent = 1,
alpha_clip = 2,
mixed = 3,
}
static string[] LODLevelLabels = new string[]
{
"All LOD Levels", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
};
static int[] LODLevelValues = new int[]
{
-1,0,1,2,3,4,5,6,7,8,9
};
static string[] transpOrOpaqueLabels = new string[]
{
"Any", "Opaque Only", "Transparent Only", "AlphaClipped Only", "Mixed Transp And Opaque Mats Only"
};
static int[] transpOrOpaqueValues = new int[]
{
(int) OpacityType.unknown, (int) OpacityType.opaque, (int) OpacityType.transparent, (int) OpacityType.alpha_clip, (int) OpacityType.mixed
};
public MB3_MeshBakerRoot _target = null;
public MonoBehaviour target
{
get { return _target; }
set { _target = (MB3_MeshBakerRoot)value; }
}
GameObject targetGO = null;
GameObject oldTargetGO = null;
MB3_TextureBaker textureBaker;
MB3_MeshBaker meshBaker;
UnityEngine.Object[] targs = new UnityEngine.Object[1];
SerializedObject serializedObject;
GUIContent GUIContentRegExpression = new GUIContent("Matches Regular Expression", @"A valid # regular express. Examples:" + "\n\n" +
@" ([A-Za-z0-9\-]+)(LOD1) matches one or more chars,numbers and hyphen ending with LOD1." + "\n\n" +
@" (Grass)([A-Za-z0-9\-\(\) ]+) matches the string 'Grass' followed by characters, numbers, hyphen, brackets or space." + "\n\n");
string helpBoxString = "";
string regExParseError = "";
bool onlyStaticObjects = false;
bool onlyEnabledObjects = false;
bool excludeMeshesWithOBuvs = true;
bool excludeMeshesAlreadyAddedToBakers = true;
int lodLevelToInclude = -1;
OpacityType transpOrOpaque = OpacityType.unknown;
int lightmapIndex = -2;
int[] lightmapValues = new int[64];
string[] lightmapDisplayValues = new string[64];
LayerMask layerMask = ~0;
int[] layerIntValues = new int[32];
string[] layerDisplayValues = new string[32];
string searchRegEx = "";
Material shaderMat = null;
Material mat = null;
bool tbFoldout = false;
bool mbFoldout = false;
MB3_MeshBakerEditorInternal mbe = new MB3_MeshBakerEditorInternal();
MB3_TextureBakerEditorInternal tbe = new MB3_TextureBakerEditorInternal();
public void SetLightmapValuesAndDisplayValues()
{
lightmapValues = new int[64];
lightmapDisplayValues = new string[64];
lightmapValues[0] = -2;
lightmapValues[1] = -1;
lightmapDisplayValues[0] = "don't filter on lightmapping";
lightmapDisplayValues[1] = "not lightmapped";
for (int i = 2; i < lightmapDisplayValues.Length; i++)
{
lightmapDisplayValues[i] = "" + (i - 2);
lightmapValues[i] = i - 2;
}
}
public void SetLayerValuesAndDisplayValues()
{
layerIntValues = new int[32];
layerDisplayValues = new string[32];
for (int i = 0; i < layerDisplayValues.Length; i++)
{
if (GetLayerName(i) != "")
{
layerDisplayValues[i] = "" + (i) + ": " + GetLayerName(i);
}
else
{
layerDisplayValues[i] = "" + (i);
}
layerIntValues[i] = i;
}
}
public void OnEnable()
{
SetLightmapValuesAndDisplayValues();
SetLayerValuesAndDisplayValues();
if (textureBaker != null)
{
serializedObject = new SerializedObject(textureBaker);
tbe.OnEnable(serializedObject);
}
else if (meshBaker != null)
{
serializedObject = new SerializedObject(meshBaker);
mbe.OnEnable(serializedObject);
}
}
public void OnDisable()
{
tbe.OnDisable();
mbe.OnDisable();
}
public void drawTabAddObjectsToBakers()
{
if (helpBoxString == null) helpBoxString = "";
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." +
"To remove, use the fields below to filter what is removed.\n" + helpBoxString, UnityEditor.MessageType.None);
target = (MB3_MeshBakerRoot)EditorGUILayout.ObjectField("Target to add objects to", target, typeof(MB3_MeshBakerRoot), true);
if (target != null)
{
targetGO = target.gameObject;
}
else
{
targetGO = null;
}
if (targetGO != oldTargetGO && targetGO != null)
{
textureBaker = targetGO.GetComponent<MB3_TextureBaker>();
meshBaker = targetGO.GetComponent<MB3_MeshBaker>();
tbe = new MB3_TextureBakerEditorInternal();
mbe = new MB3_MeshBakerEditorInternal();
oldTargetGO = targetGO;
if (textureBaker != null)
{
serializedObject = new SerializedObject(textureBaker);
tbe.OnEnable(serializedObject);
}
else if (meshBaker != null)
{
serializedObject = new SerializedObject(meshBaker);
mbe.OnEnable(serializedObject);
}
}
EditorGUIUtility.labelWidth = 300;
onlyStaticObjects = EditorGUILayout.Toggle("Only Static Objects", onlyStaticObjects);
onlyEnabledObjects = EditorGUILayout.Toggle("Only Enabled Objects", onlyEnabledObjects);
excludeMeshesWithOBuvs = EditorGUILayout.Toggle("Exclude meshes with out-of-bounds UVs", excludeMeshesWithOBuvs);
excludeMeshesAlreadyAddedToBakers = EditorGUILayout.Toggle("Exclude GameObjects already added to bakers", excludeMeshesAlreadyAddedToBakers);
lodLevelToInclude = EditorGUILayout.IntPopup("Only include objects on LOD Level", lodLevelToInclude, LODLevelLabels, LODLevelValues);
mat = (Material)EditorGUILayout.ObjectField("Using Material", mat, typeof(Material), true);
shaderMat = (Material)EditorGUILayout.ObjectField("Using Shader", shaderMat, typeof(Material), true);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Using Lightmap Index ");
lightmapIndex = EditorGUILayout.IntPopup(lightmapIndex,
lightmapDisplayValues,
lightmapValues);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Using Layers");
layerMask.value = EditorGUILayout.MaskField(layerMask.value, layerDisplayValues);
EditorGUILayout.EndHorizontal();
transpOrOpaque = (OpacityType) EditorGUILayout.IntPopup("Only Include Transparent Or Opaque", (int) transpOrOpaque, transpOrOpaqueLabels, transpOrOpaqueValues);
if (regExParseError != null && regExParseError.Length > 0)
{
EditorGUILayout.HelpBox("Error In Regular Expression:\n" + regExParseError, MessageType.Error);
}
searchRegEx = EditorGUILayout.TextField(GUIContentRegExpression, searchRegEx);
EditorGUILayout.Separator();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Add Selected Meshes To Target"))
{
addSelectedObjects();
}
if (GUILayout.Button("Remove Matching Meshes From Target"))
{
removeSelectedObjects();
}
EditorGUILayout.EndHorizontal();
if (textureBaker != null)
{
MB_EditorUtil.DrawSeparator();
tbFoldout = EditorGUILayout.Foldout(tbFoldout, "Texture Baker");
if (tbFoldout)
{
if (targs == null) targs = new UnityEngine.Object[1];
targs[0] = textureBaker;
tbe.DrawGUI(serializedObject, textureBaker, targs, typeof(MB3_MeshBakerEditorWindow));
}
}
if (meshBaker != null)
{
MB_EditorUtil.DrawSeparator();
mbFoldout = EditorGUILayout.Foldout(mbFoldout, "Mesh Baker");
if (mbFoldout)
{
if (targs == null) targs = new UnityEngine.Object[1];
targs[0] = meshBaker;
mbe.DrawGUI(serializedObject, (MB3_MeshBaker)meshBaker, targs, typeof(MB3_MeshBakerEditorWindow));
}
}
}
List<GameObject> GetFilteredList(bool addingObjects)
{
List<GameObject> newMomObjs = new List<GameObject>();
MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
if (mom == null)
{
Debug.LogError("Must select a target MeshBaker");
return newMomObjs;
}
GameObject dontAddMe = null;
Renderer r = MB_Utility.GetRenderer(mom.gameObject);
if (r != null)
{ //make sure that this MeshBaker object is not in list
dontAddMe = r.gameObject;
}
MB3_MeshBakerRoot[] allBakers = (MB3_MeshBakerRoot[])MBVersion.FindSceneObjectsOfType(typeof(MB3_MeshBakerRoot));
HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
if (addingObjects)
{
for (int i = 0; i < allBakers.Length; i++)
{
List<GameObject> objsToCombine = allBakers[i].GetObjectsToCombine();
for (int j = 0; j < objsToCombine.Count; j++)
{
if (objsToCombine[j] != null) objectsAlreadyIncludedInBakers.Add(objsToCombine[j]);
}
}
}
GameObject[] gos = Selection.gameObjects;
if (gos.Length == 0)
{
Debug.LogWarning("No objects selected in hierarchy view. Nothing added. Try selecting some objects.");
return newMomObjs;
}
List<GameObject> mrs = new List<GameObject>();
for (int i = 0; i < gos.Length; i++)
{
GameObject go = gos[i];
Renderer[] rs = go.GetComponentsInChildren<Renderer>(true);
for (int j = 0; j < rs.Length; j++)
{
if (rs[j] is MeshRenderer || rs[j] is SkinnedMeshRenderer)
{
mrs.Add(rs[j].gameObject);
}
}
}
newMomObjs = FilterList(mrs, objectsAlreadyIncludedInBakers, dontAddMe, addingObjects);
return newMomObjs;
}
int GetLODLevelForRenderer(Renderer r)
{
if (r != null)
{
LODGroup lodGroup = r.GetComponentInParent<LODGroup>();
if (lodGroup != null)
{
LOD[] lods = lodGroup.GetLODs();
for (int lodIdx = 0; lodIdx < lods.Length; lodIdx++)
{
Renderer[] rs = lods[lodIdx].renderers;
for (int j = 0; j < rs.Length; j++)
{
if (rs[j] == r)
{
return lodIdx;
}
}
}
}
}
return 0;
}
int GetLayerValue(GameObject go)
{
return go.layer;
}
string GetLayerName(int layerNum)
{
string layerName = LayerMask.LayerToName(layerNum);
return "" + layerName;
}
List<GameObject> FilterList(List<GameObject> mrss,
HashSet<GameObject> objectsAlreadyIncludedInBakers,
GameObject dontAddMe,
bool addingObjects)
{
int numInSelection = 0;
int numStaticExcluded = 0;
int numEnabledExcluded = 0;
int numLightmapExcluded = 0;
int numLayerExcluded = 0;
int numLodLevelExcluded = 0;
int numOBuvExcluded = 0;
int numMatExcluded = 0;
int numShaderExcluded = 0;
int numRegExExcluded = 0;
int numAlreadyIncludedExcluded = 0;
int numTranspOrOpaqueExluded = 0;
System.Text.RegularExpressions.Regex regex = null;
if (searchRegEx != null && searchRegEx.Length > 0)
{
try
{
regex = new System.Text.RegularExpressions.Regex(searchRegEx);
regExParseError = "";
}
catch (Exception ex)
{
regExParseError = ex.Message;
}
}
Dictionary<int, MB_Utility.MeshAnalysisResult> meshAnalysisResultsCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>(); //cache results
List<GameObject> newMomObjs = new List<GameObject>();
for (int j = 0; j < mrss.Count; j++)
{
if (mrss[j] == null)
{
continue;
}
Renderer mrs = mrss[j].GetComponent<Renderer>();
int layerValue = GetLayerValue(mrss[j]);
if (mrs is MeshRenderer || mrs is SkinnedMeshRenderer)
{
if (mrs.GetComponent<TextMesh>() != null)
{
continue; //don't add TextMeshes
}
numInSelection++;
if (!newMomObjs.Contains(mrs.gameObject))
{
bool addMe = true;
if (!mrs.gameObject.isStatic && onlyStaticObjects)
{
numStaticExcluded++;
addMe = false;
continue;
}
if ((!mrs.enabled || !mrs.gameObject.activeInHierarchy) && onlyEnabledObjects)
{
numEnabledExcluded++;
addMe = false;
continue;
}
if (lightmapIndex != -2)
{
if (mrs.lightmapIndex != lightmapIndex)
{
numLightmapExcluded++;
addMe = false;
continue;
}
}
if (layerMask != 0)
{
int layerBit = 1 << layerValue;
//Debug.Log("LayerBit: " + layerBit);
if ((layerMask & layerBit) == 0)
{
numLayerExcluded++;
addMe = false;
continue;
}
}
else
{
numLayerExcluded++;
addMe = false;
continue;
}
if (lodLevelToInclude == -1)
{
// not filtering on LODLevel
}
else
{
if (GetLODLevelForRenderer(mrs) != lodLevelToInclude)
{
numLodLevelExcluded++;
addMe = false;
continue;
}
}
if (transpOrOpaque == OpacityType.unknown)
{
// not filtering on transp or opaque
}
else
{
if (!RendererTransparentOrOpaqueMatches(mrs, transpOrOpaque))
{
numTranspOrOpaqueExluded++;
addMe = false;
continue;
}
}
// only do this check when adding objects. If removing objects shouldn't do it
if (addingObjects &&
excludeMeshesAlreadyAddedToBakers &&
objectsAlreadyIncludedInBakers.Contains(mrs.gameObject))
{
numAlreadyIncludedExcluded++;
addMe = false;
continue;
}
Mesh mm = MB_Utility.GetMesh(mrs.gameObject);
if (mm != null)
{
MB_Utility.MeshAnalysisResult mar;
if (!meshAnalysisResultsCache.TryGetValue(mm.GetInstanceID(), out mar))
{
MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
meshAnalysisResultsCache.Add(mm.GetInstanceID(), mar);
}
if (mar.hasOutOfBoundsUVs && excludeMeshesWithOBuvs)
{
numOBuvExcluded++;
addMe = false;
continue;
}
}
if (shaderMat != null)
{
Material[] nMats = mrs.sharedMaterials;
bool usesShader = false;
foreach (Material nMat in nMats)
{
if (nMat != null && nMat.shader == shaderMat.shader)
{
usesShader = true;
}
}
if (!usesShader)
{
numShaderExcluded++;
addMe = false;
continue;
}
}
if (mat != null)
{
Material[] nMats = mrs.sharedMaterials;
bool usesMat = false;
foreach (Material nMat in nMats)
{
if (nMat == mat)
{
usesMat = true;
}
}
if (!usesMat)
{
numMatExcluded++;
addMe = false;
continue;
}
}
if (regex != null)
{
if (!regex.IsMatch(mrs.gameObject.name))
{
numRegExExcluded++;
addMe = false;
continue;
}
}
if (addMe && mrs.gameObject != dontAddMe)
{
if (!newMomObjs.Contains(mrs.gameObject))
{
newMomObjs.Add(mrs.gameObject);
}
}
}
}
}
System.Text.StringBuilder sb = new System.Text.StringBuilder();
//sb.AppendFormat("Total objects in selection {0}\n", numInSelection);
//Debug.Log( "Total objects in selection " + numInSelection);
if (numStaticExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they were not static\n", numStaticExcluded);
Debug.Log(numStaticExcluded + " objects were excluded because they were not static\n");
}
if (numEnabledExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they were disabled\n", numEnabledExcluded);
Debug.Log(numEnabledExcluded + " objects were excluded because they were disabled\n");
}
if (numOBuvExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they had out of bounds uvs\n", numOBuvExcluded);
Debug.Log(numOBuvExcluded + " objects were excluded because they had out of bounds uvs\n");
}
if (numLightmapExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not match lightmap filter.\n", numLightmapExcluded);
Debug.Log(numLightmapExcluded + " objects did not match lightmap filter.\n");
}
if (numLayerExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not use the selected layers. \n",
numLayerExcluded);
Debug.Log(numLayerExcluded + " objects were excluded because they did not use the selected layers");
}
if (numLodLevelExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not match the selected LOD level filter.\n", numLodLevelExcluded);
Debug.Log(numLodLevelExcluded + " objects did not match LOD level filter.\n");
}
if (numShaderExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not use the selected shader.\n", numShaderExcluded);
Debug.Log(numShaderExcluded + " objects were excluded because they did not use the selected shader.\n");
}
if (numMatExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not use the selected material.\n", numMatExcluded);
Debug.Log(numMatExcluded + " objects were excluded because they did not use the selected material.\n");
}
if (numTranspOrOpaqueExluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they the didn't match transparent or opaque filter.\n", numTranspOrOpaqueExluded);
Debug.LogFormat(" {0} objects were excluded because they the didn't match transparent or opaque filter.\n", numTranspOrOpaqueExluded);
}
if (numRegExExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did not match the regular expression.\n", numRegExExcluded);
Debug.Log(numRegExExcluded + " objects were excluded because they did not match the regular expression.\n");
}
if (numAlreadyIncludedExcluded > 0)
{
sb.AppendFormat(" {0} objects were excluded because they did were already included in other bakers.\n", numAlreadyIncludedExcluded);
Debug.Log(numAlreadyIncludedExcluded + " objects were excluded because they did were already included in other bakers.\n");
}
helpBoxString = sb.ToString();
return newMomObjs;
}
private bool RendererTransparentOrOpaqueMatches(Renderer mrs, OpacityType transpOrOpaque)
{
MBVersion.PipelineType currentRenderPipeline = MBVersion.DetectPipeline();
OpacityType isMatTranspOrOpaque = OpacityType.unknown;
if (mrs == null)
{
return false;
}
for (int i = 0; i < mrs.sharedMaterials.Length; i++)
{
Material m = mrs.sharedMaterials[i];
if (m == null)
{
continue;
}
OpacityType isCurMatTranspOrOpaque;
if (currentRenderPipeline == MBVersion.PipelineType.URP)
{
isCurMatTranspOrOpaque = _GetOpaqueOrTransparentURP(m);
}
else if (currentRenderPipeline == MBVersion.PipelineType.HDRP)
{
isCurMatTranspOrOpaque = _GetOpaqueOrTransparentHDRP(m);
}
else
{
// Defualt or unknown pipeline
isCurMatTranspOrOpaque = _GetOpaqueOrTransparentBuiltInOrUnknownRP(m);
}
if (isMatTranspOrOpaque == OpacityType.unknown)
{
isMatTranspOrOpaque = isCurMatTranspOrOpaque;
}
else if (isMatTranspOrOpaque != isCurMatTranspOrOpaque)
{
// was previously set to something different. Renderer has mixed materials.
isMatTranspOrOpaque = OpacityType.mixed;
break;
}
}
if (isMatTranspOrOpaque == OpacityType.unknown)
{
return false;
}
else
{
return isMatTranspOrOpaque == transpOrOpaque;
}
}
private OpacityType _GetOpaqueOrTransparentBuiltInOrUnknownRP(Material m)
{
bool isTransparent = m.renderQueue >= (int)RenderQueue.Transparent;
bool isAlphaClipped = m.renderQueue == (int)RenderQueue.AlphaTest;
if (isAlphaClipped)
{
return OpacityType.alpha_clip;
}
else if (isTransparent)
{
return OpacityType.transparent;
}
else
{
return OpacityType.opaque;
}
}
private OpacityType _GetOpaqueOrTransparentHDRP(Material m)
{
if (m.HasProperty("_SurfaceType"))
{
float surfaceType = m.GetFloat("_SurfaceType");
if (surfaceType == 0)
{
if (m.HasProperty("_AlphaCutoffEnable") && m.GetFloat("_AlphaCutoffEnable") == 1)
{
return OpacityType.alpha_clip;
}
else
{
return OpacityType.opaque;
}
}
else if (surfaceType == 1)
{
return OpacityType.transparent;
}
}
return _GetOpaqueOrTransparentBuiltInOrUnknownRP(m);
}
private OpacityType _GetOpaqueOrTransparentURP(Material m)
{
if (m.HasProperty("_Surface"))
{
float surfaceType = m.GetFloat("_Surface");
if (surfaceType == 0)
{
if (m.HasProperty("_AlphaClip") && m.GetFloat("_AlphaClip") == 1)
{
return OpacityType.alpha_clip;
}
else
{
return OpacityType.opaque;
}
}
else if (surfaceType == 1)
{
return OpacityType.transparent;
}
}
return _GetOpaqueOrTransparentBuiltInOrUnknownRP(m);
}
void removeSelectedObjects()
{
MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
if (mom == null)
{
Debug.LogError("Must select a target MeshBaker");
return;
}
List<GameObject> objsToCombine = mom.GetObjectsToCombine();
GameObject dontAddMe = null;
Renderer r = MB_Utility.GetRenderer(mom.gameObject);
if (r != null)
{ //make sure that this MeshBaker object is not in list
dontAddMe = r.gameObject;
}
List<GameObject> objsSelectedMatchingFilter = GetFilteredList(addingObjects: false);
Debug.Log("Matching filter " + objsSelectedMatchingFilter.Count);
List<GameObject> objsToRemove = new List<GameObject>();
for (int i = 0; i < objsSelectedMatchingFilter.Count; i++)
{
if (objsToCombine.Contains(objsSelectedMatchingFilter[i]))
{
objsToRemove.Add(objsSelectedMatchingFilter[i]);
}
}
MBVersionEditor.RegisterUndo(mom, "Remove Objects");
for (int i = 0; i < objsToRemove.Count; i++)
{
objsToCombine.Remove(objsToRemove[i]);
}
SerializedObject so = new SerializedObject(mom);
so.SetIsDifferentCacheDirty();
Debug.Log("Removed " + objsToRemove.Count + " objects from " + mom.name);
helpBoxString += String.Format("\nRemoved {0} objects from {1}", objsToRemove.Count, mom.name);
}
void addSelectedObjects()
{
MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;
if (mom == null)
{
Debug.LogError("Must select a target MeshBaker or TextureBaker to add objects to");
return;
}
List<GameObject> newMomObjs = GetFilteredList(addingObjects: true);
MBVersionEditor.RegisterUndo(mom, "Add Objects");
List<GameObject> momObjs = mom.GetObjectsToCombine();
int numAdded = 0;
int numAlreadyInList = 0;
for (int i = 0; i < newMomObjs.Count; i++)
{
if (!momObjs.Contains(newMomObjs[i]))
{
momObjs.Add(newMomObjs[i]);
numAdded++;
}
else
{
numAlreadyInList++;
}
}
SerializedObject so = new SerializedObject(mom);
so.SetIsDifferentCacheDirty();
if (numAlreadyInList > 0)
{
Debug.Log(String.Format("Skipped adding {0} objects to Target because these objects had already been added to this Target. ", numAlreadyInList));
}
if (numAdded == 0)
{
Debug.LogWarning("Added 0 objects. Make sure some or all objects are selected in the hierarchy view. Also check the 'Only Static Objects', 'Using Material' and 'Using Shader' settings");
}
else
{
Debug.Log(string.Format("Added {0} objects to {1}. ", numAdded, mom.name));
}
helpBoxString += String.Format("\nAdded {0} objects to {1}", numAdded, mom.name);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 4caf9fbf2fe59bf479dc70cb752462a6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditorWindowAddObjectsTab.cs
uploadId: 797180
@@ -0,0 +1,875 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_MeshBakerEditorWindowAnalyseSceneTab
{
public struct ResultPagination
{
public string nameOfNumToShowControl;
public bool foldoutIsOpen;
public int firstIdxToShow;
public int numToShow;
public int numToShow_whenEditing;
}
const int NUM_FILTERS = 5;
const int DEFAULT_NUM_TO_SHOW = 10;
bool writeReportFile = false;
bool splitAtlasesSoMeshesFit = false;
int atlasSize = MB2_TexturePacker.MAX_ATLAS_SIZE;
string generate_AssetsFolder = "";
List<List<GameObjectFilterInfo>> sceneAnalysisResults = new List<List<GameObjectFilterInfo>>();
ResultPagination[] sceneAnalysisResultsFoldouts = new ResultPagination[0];
int[] groupByFilterIdxs = new int[NUM_FILTERS];
string[] groupByOptionNames;
IGroupByFilter[] groupByOptionFilters;
IGroupByFilter[] filters;
Vector2 scrollPos2 = Vector2.zero;
string _controlThatHadFocusLastFrame = "";
GUIContent gc_atlasSize = new GUIContent("Max Atlas Size", "");
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.");
public static bool InterfaceFilter(Type typeObj, System.Object criteriaObj)
{
return typeObj.ToString() == criteriaObj.ToString();
}
void populateGroupByFilters()
{
string qualifiedInterfaceName = "DigitalOpus.MB.MBEditor.IGroupByFilter";
var interfaceFilter = new TypeFilter(InterfaceFilter);
List<Type> types = new List<Type>();
foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
{
System.Collections.IEnumerable typesIterator = null;
try
{
typesIterator = ass.GetTypes();
}
catch (Exception e)
{
//Debug.Log("The assembly that I could not read types for was: " + ass.GetName());
//suppress error
e.Equals(null);
}
if (typesIterator != null)
{
foreach (Type ty in ass.GetTypes())
{
var myInterfaces = ty.FindInterfaces(interfaceFilter, qualifiedInterfaceName);
if (myInterfaces.Length > 0)
{
types.Add(ty);
}
}
}
}
List<string> filterNames = new List<string>();
List<IGroupByFilter> filters = new List<IGroupByFilter>();
filterNames.Add("None");
filters.Add(null);
foreach (Type tt in types)
{
if (!tt.IsAbstract && !tt.IsInterface)
{
IGroupByFilter instance = (IGroupByFilter)System.Activator.CreateInstance(tt);
filterNames.Add(instance.GetName());
filters.Add(instance);
}
}
groupByOptionNames = filterNames.ToArray();
groupByOptionFilters = filters.ToArray();
}
public void drawTabAnalyseScene(Rect position)
{
//first time we are displaying collect the filters
if (groupByOptionNames == null || groupByOptionNames.Length == 0)
{
//var types = AppDomain.CurrentDomain.GetAssemblies()
// .SelectMany(s => s.GetTypes())
// .Where(p => type.IsAssignableFrom(p));
populateGroupByFilters();
//set filter initial values
for (int i = 0; i < groupByOptionFilters.Length; i++)
{
if (groupByOptionFilters[i] is GroupByShader)
{
groupByFilterIdxs[0] = i;
break;
}
}
for (int i = 0; i < groupByOptionFilters.Length; i++)
{
if (groupByOptionFilters[i] is GroupByStatic)
{
groupByFilterIdxs[1] = i;
break;
}
}
for (int i = 0; i < groupByOptionFilters.Length; i++)
{
if (groupByOptionFilters[i] is GroupByRenderType)
{
groupByFilterIdxs[2] = i;
break;
}
}
for (int i = 0; i < groupByOptionFilters.Length; i++)
{
if (groupByOptionFilters[i] is GroupByOutOfBoundsUVs)
{
groupByFilterIdxs[3] = i;
break;
}
}
groupByFilterIdxs[4] = 0; //none
}
if (groupByFilterIdxs == null || groupByFilterIdxs.Length < NUM_FILTERS)
{
groupByFilterIdxs = new int[]{
0,0,0,0,0
};
}
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);
groupByFilterIdxs[0] = EditorGUILayout.Popup("Group By:", groupByFilterIdxs[0], groupByOptionNames);
for (int i = 1; i < NUM_FILTERS; i++)
{
groupByFilterIdxs[i] = EditorGUILayout.Popup("Then Group By:", groupByFilterIdxs[i], groupByOptionNames);
}
EditorGUILayout.BeginHorizontal();
float oldLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 300;
splitAtlasesSoMeshesFit = EditorGUILayout.Toggle(gc_splitAtlasesSoMeshesFit, splitAtlasesSoMeshesFit);
EditorGUIUtility.labelWidth = oldLabelWidth;
bool enableAtlasField = true;
if (splitAtlasesSoMeshesFit)
{
enableAtlasField = false;
}
EditorGUI.BeginDisabledGroup(enableAtlasField);
atlasSize = EditorGUILayout.IntField(gc_atlasSize, atlasSize);
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select Folder For Combined Material Assets"))
{
generate_AssetsFolder = EditorUtility.SaveFolderPanel("Create Combined Material Assets In Folder", "", "");
generate_AssetsFolder = "Assets" + generate_AssetsFolder.Replace(Application.dataPath, "") + "/";
}
EditorGUILayout.LabelField("Folder: " + generate_AssetsFolder);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("List Shaders In Scene"))
{
EditorUtility.DisplayProgressBar("Analysing Scene", "", .05f);
try
{
listMaterialsInScene();
}
catch (Exception ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
}
finally
{
EditorUtility.ClearProgressBar();
}
}
if (GUILayout.Button("Bake Every MeshBaker In Scene"))
{
try
{
MB3_TextureBaker[] texBakers = (MB3_TextureBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_TextureBaker));
for (int i = 0; i < texBakers.Length; i++)
{
texBakers[i].CreateAtlases(updateProgressBar, true, new MB3_EditorMethods());
}
MB3_MeshBakerCommon[] mBakers = (MB3_MeshBakerCommon[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_MeshBakerCommon));
bool createTempMaterialBakeResult;
for (int i = 0; i < mBakers.Length; i++)
{
if (mBakers[i].textureBakeResults != null)
{
MB3_MeshBakerEditorFunctions.BakeIntoCombined(mBakers[i], out createTempMaterialBakeResult);
}
}
}
catch (Exception ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
}
finally
{
EditorUtility.ClearProgressBar();
}
}
EditorGUILayout.EndHorizontal();
if (sceneAnalysisResults.Count > 0)
{
float height = position.height - 150f;
if (height < 500f) height = 500f;
MB_EditorUtil.DrawSeparator();
scrollPos2 = EditorGUILayout.BeginScrollView(scrollPos2, false, true); //(scrollPos2,, GUILayout.Width(position.width - 20f), GUILayout.Height(height));
EditorGUILayout.LabelField("Shaders In Scene", EditorStyles.boldLabel);
GUILayout.Space(15);
EditorGUILayout.Separator();
for (int i = 0; i < sceneAnalysisResults.Count; i++)
{
DrawGroupOfSimilarRenderers(sceneAnalysisResults[i], ref sceneAnalysisResultsFoldouts[i]);
}
EditorGUILayout.EndScrollView();
MB_EditorUtil.DrawSeparator();
}
{
// Detect if we just finished editing one of the pagination numToShow boxes.
int idxThatHadControlLastFrame = -1;
int idxThatHasControlThisFrame = -1;
for (int i = 0; i < sceneAnalysisResultsFoldouts.Length; i++)
{
if (sceneAnalysisResultsFoldouts[i].nameOfNumToShowControl.Equals(_controlThatHadFocusLastFrame))
{
idxThatHadControlLastFrame = i;
}
if (sceneAnalysisResultsFoldouts[i].nameOfNumToShowControl.Equals(GUI.GetNameOfFocusedControl()))
{
idxThatHasControlThisFrame = i;
}
}
if (idxThatHadControlLastFrame != -1 &&
idxThatHadControlLastFrame != idxThatHasControlThisFrame)
{
// We just lost focus on a numToShow text box. Update the value.
sceneAnalysisResultsFoldouts[idxThatHadControlLastFrame].numToShow_whenEditing = Mathf.Clamp(sceneAnalysisResultsFoldouts[idxThatHadControlLastFrame].numToShow_whenEditing, 1, 300);
sceneAnalysisResultsFoldouts[idxThatHadControlLastFrame].numToShow = sceneAnalysisResultsFoldouts[idxThatHadControlLastFrame].numToShow_whenEditing;
}
}
_controlThatHadFocusLastFrame = GUI.GetNameOfFocusedControl();
}
void DrawGroupOfSimilarRenderers(List<GameObjectFilterInfo> gows, ref ResultPagination paginationInfo)
{
string descr = String.Format("Objs={0} AtlasIndex={1} {2}", gows.Count, gows[0].atlasIndex, gows[0].GetDescription(filters, gows[0]));
GUI.color = new Color(.5f, 1f, .5f);
EditorGUILayout.LabelField(descr, EditorStyles.boldLabel);
GUI.color = Color.white;
EditorGUI.indentLevel += 1;
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Generate Baker", GUILayout.Width(200)))
{
createAndSetupBaker(gows, generate_AssetsFolder);
}
if (GUILayout.Button("Select All", GUILayout.Width(200)))
{
UnityEngine.Object[] selected = new UnityEngine.Object[gows.Count];
for (int j = 0; j < gows.Count; j++)
{
selected[j] = gows[j].go;
}
Selection.objects = selected;
SceneView.lastActiveSceneView.FrameSelected();
}
EditorGUILayout.EndHorizontal();
string filterDescription = "Unknown";
if (gows.Count > 0)
{
filterDescription = gows[0].GetDescription(filters, gows[0]);
}
paginationInfo.foldoutIsOpen = EditorGUILayout.Foldout(paginationInfo.foldoutIsOpen, filterDescription);
if (paginationInfo.foldoutIsOpen)
{
EditorGUI.indentLevel += 1;
int numPerPage = paginationInfo.numToShow;
if (numPerPage < 1) numPerPage = 1;
if (numPerPage > 256) numPerPage = 256;
int firstToDisplay = paginationInfo.firstIdxToShow;
if (firstToDisplay >= gows.Count) firstToDisplay = gows.Count - 1;
if (firstToDisplay < 0) firstToDisplay = 0;
int lastToDisplay = firstToDisplay + numPerPage;
if (lastToDisplay > gows.Count) lastToDisplay = gows.Count;
for (int resIdx = firstToDisplay; resIdx < lastToDisplay; resIdx++)
{
if (gows[resIdx].go != null)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select", new GUILayoutOption[] { GUILayout.MaxWidth(100) }))
{
Selection.activeGameObject = gows[resIdx].go;
}
EditorGUILayout.LabelField(gows[resIdx].go.name);
EditorGUILayout.EndHorizontal();
}
}
EditorGUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent("Displaying " + (firstToDisplay + 1) + " to " + lastToDisplay + " of " + gows.Count + " num to show:"), GUILayout.ExpandWidth(false));
GUI.SetNextControlName(paginationInfo.nameOfNumToShowControl);
if (GUI.GetNameOfFocusedControl().Equals(paginationInfo.nameOfNumToShowControl))
{
// Use a temporary variable for storing what the user is typing when they are editing a numToShow box
// We don't want to change the number of rows we are displaying for every keystroke. Only when they
// Leave the text box.
paginationInfo.numToShow_whenEditing = EditorGUILayout.IntField(paginationInfo.numToShow_whenEditing, new GUILayoutOption[] { GUILayout.MaxWidth(100) });
paginationInfo.numToShow_whenEditing = Mathf.Clamp(paginationInfo.numToShow_whenEditing, 1, 300);
} else
{
paginationInfo.numToShow = EditorGUILayout.IntField(paginationInfo.numToShow, new GUILayoutOption[] { GUILayout.MaxWidth(100) });
}
if (gows.Count > numPerPage)
{
if (firstToDisplay > 0)
{
if (GUILayout.Button(" Previous ", GUILayout.MaxWidth(200)))
{
paginationInfo.firstIdxToShow -= numPerPage;
if (paginationInfo.firstIdxToShow < 0) paginationInfo.firstIdxToShow = 0;
}
}
if (lastToDisplay < gows.Count)
{
if (GUILayout.Button(" Next ", GUILayout.MaxWidth(200)))
{
paginationInfo.firstIdxToShow += numPerPage;
if (paginationInfo.firstIdxToShow >= gows.Count) paginationInfo.firstIdxToShow = gows.Count - 1;
if (paginationInfo.firstIdxToShow < 0) paginationInfo.firstIdxToShow = 0;
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUI.indentLevel -= 1;
}
EditorGUI.indentLevel -= 1;
GUILayout.Space(15);
EditorGUILayout.Separator();
}
int GetLODLevelForRenderer(Renderer r)
{
if (r != null)
{
LODGroup lodGroup = r.GetComponentInParent<LODGroup>();
if (lodGroup != null)
{
LOD[] lods = lodGroup.GetLODs();
for (int lodIdx = 0; lodIdx < lods.Length; lodIdx++)
{
Renderer[] rs = lods[lodIdx].renderers;
for (int j = 0; j < rs.Length; j++)
{
if (rs[j] == r)
{
return lodIdx;
}
}
}
}
}
return 0;
}
void listMaterialsInScene()
{
if (!ValidateGroupByFields()) return;
if (groupByOptionFilters == null)
{
populateGroupByFilters();
}
List<IGroupByFilter> gbfs = new List<IGroupByFilter>();
for (int i = 0; i < groupByFilterIdxs.Length; i++)
{
if (groupByFilterIdxs[i] != 0)
{
gbfs.Add(groupByOptionFilters[groupByFilterIdxs[i]]);
}
}
filters = gbfs.ToArray();
//Get All Objects Already In a list of objects to be combined
EditorUtility.DisplayProgressBar("Analysing Scene", "Finding Existing MeshBakers In Scene", .1f);
MB3_MeshBakerRoot[] allBakers = (MB3_MeshBakerRoot[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_MeshBakerRoot));
HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
for (int i = 0; i < allBakers.Length; i++)
{
List<GameObject> objsToCombine = allBakers[i].GetObjectsToCombine();
for (int j = 0; j < objsToCombine.Count; j++)
{
if (objsToCombine[j] != null) objectsAlreadyIncludedInBakers.Add(objsToCombine[j]);
}
}
//collect all renderers in scene
List<GameObjectFilterInfo> gameObjects = new List<GameObjectFilterInfo>();
Renderer[] rs = (Renderer[]) MBVersion.FindSceneObjectsOfType(typeof(Renderer));
// Profile.StartProfile("listMaterialsInScene1");
EditorUtility.DisplayProgressBar("Analysing Scene", "Collecting Renderers", .25f);
for (int i = 0; i < rs.Length; i++)
{
Renderer r = rs[i];
if (r is MeshRenderer || r is SkinnedMeshRenderer)
{
if (r.GetComponent<TextMesh>() != null)
{
continue; //don't add TextMeshes
}
GameObjectFilterInfo goaw = new GameObjectFilterInfo(r.gameObject, objectsAlreadyIncludedInBakers, filters);
if (goaw.materials.Length > 0) //don't consider renderers with no materials
{
gameObjects.Add(goaw);
EditorUtility.DisplayProgressBar("Analysing Scene", "Collecting Renderer For " + r.name, .1f);
}
}
}
//analyse meshes
Dictionary<int, MB_Utility.MeshAnalysisResult> meshAnalysisResultCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>();
int totalVerts = 0;
for (int i = 0; i < gameObjects.Count; i++)
{
string rpt = String.Format("Processing {0} [{1} of {2}]", gameObjects[i].go.name, i, gameObjects.Count);
EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " A", .6f);
Mesh mm = MB_Utility.GetMesh(gameObjects[i].go);
int nVerts = 0;
if (mm != null)
{
nVerts += mm.vertexCount;
MB_Utility.MeshAnalysisResult mar;
if (!meshAnalysisResultCache.TryGetValue(mm.GetInstanceID(), out mar))
{
EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Check Out Of Bounds UVs", .6f);
MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
//Rect dummy = mar.uvRect;
MB_Utility.doSubmeshesShareVertsOrTris(mm, ref mar);
meshAnalysisResultCache.Add(mm.GetInstanceID(), mar);
}
if (mar.hasOutOfBoundsUVs)
{
int w = (int)mar.uvRect.width;
int h = (int)mar.uvRect.height;
gameObjects[i].outOfBoundsUVs = true;
gameObjects[i].warning.AppendLine(" [WARNING: has uvs outside the range (0,1) tex is tiled " + w + "x" + h + " times]");
}
if (mar.hasOverlappingSubmeshVerts)
{
gameObjects[i].submeshesOverlap = true;
gameObjects[i].warning.AppendLine(" [WARNING: Submeshes share verts or triangles. 'Multiple Combined Materials' feature may not work.]");
}
}
totalVerts += nVerts;
EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Validate OBuvs Multi Material", .6f);
Renderer mr = gameObjects[i].go.GetComponent<Renderer>();
if (!MB_Utility.AreAllSharedMaterialsDistinct(mr.sharedMaterials))
{
gameObjects[i].warning.AppendLine(" [WARNING: Object uses same material on multiple submeshes. This may produce poor results when used with multiple materials or Consider Mesh UVs.]");
}
}
List<GameObjectFilterInfo> objsNotAddedToBaker = new List<GameObjectFilterInfo>();
Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap = sortIntoBakeGroups3(gameObjects, objsNotAddedToBaker, filters, splitAtlasesSoMeshesFit, atlasSize);
sceneAnalysisResults = new List<List<GameObjectFilterInfo>>();
foreach (GameObjectFilterInfo gow in gs2bakeGroupMap.Keys)
{
List<List<GameObjectFilterInfo>> gows = gs2bakeGroupMap[gow];
for (int i = 0; i < gows.Count; i++) //if split atlases by what fits in atlas
{
sceneAnalysisResults.Add(gows[i]);
}
}
sceneAnalysisResultsFoldouts = new ResultPagination[sceneAnalysisResults.Count];
for (int i = 0; i < sceneAnalysisResults.Count; i++)
{
sceneAnalysisResultsFoldouts[i].nameOfNumToShowControl = "numToShow_" + i;
sceneAnalysisResultsFoldouts[i].foldoutIsOpen = true;
sceneAnalysisResultsFoldouts[i].numToShow = DEFAULT_NUM_TO_SHOW;
sceneAnalysisResultsFoldouts[i].numToShow_whenEditing = DEFAULT_NUM_TO_SHOW;
}
if (writeReportFile)
{
string fileName = Application.dataPath + "/MeshBakerSceneAnalysisReport.txt";
try
{
System.IO.File.WriteAllText(fileName, generateSceneAnalysisReport(gs2bakeGroupMap, objsNotAddedToBaker));
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));
}
catch (Exception e)
{
e.GetHashCode(); //supress compiler warning
Debug.Log("Failed to write file: " + fileName);
}
}
}
string generateSceneAnalysisReport(Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap, List<GameObjectFilterInfo> objsNotAddedToBaker)
{
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";
outStr += "\t\tOBJECT NAME\tLIGHTMAP INDEX\tSTATIC\tOVERLAPPING SUBMESHES\tOUT-OF-BOUNDS UVs\tNUM MATS\tMATERIAL\tWARNINGS\n";
int totalVerts = 0;
string outStr2 = "";
foreach (List<List<GameObjectFilterInfo>> goss in gs2bakeGroupMap.Values)
{
for (int atlasIdx = 0; atlasIdx < goss.Count; atlasIdx++)
{
List<GameObjectFilterInfo> gos = goss[atlasIdx];
outStr2 = "";
totalVerts = 0;
gos.Sort();
for (int i = 0; i < gos.Count; i++)
{
totalVerts += gos[i].numVerts;
string matStr = "";
Renderer mr = gos[i].go.GetComponent<Renderer>();
foreach (Material mmm in mr.sharedMaterials)
{
matStr += "[" + mmm + "] ";
}
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";
}
outStr2 = "\t" + gos[0].shaderName + " (" + totalVerts + " verts): \n" + outStr2;
outStr += outStr2;
}
}
if (objsNotAddedToBaker.Count > 0)
{
outStr += "Other objects\n";
string shaderName = "";
totalVerts = 0;
List<GameObjectFilterInfo> gos1 = objsNotAddedToBaker;
gos1.Sort();
outStr2 = "";
for (int i = 0; i < gos1.Count; i++)
{
if (!shaderName.Equals(objsNotAddedToBaker[i].shaderName))
{
outStr2 += "\t" + gos1[0].shaderName + "\n";
shaderName = objsNotAddedToBaker[i].shaderName;
}
totalVerts += gos1[i].numVerts;
string matStr = "";
Renderer mr = gos1[i].go.GetComponent<Renderer>();
foreach (Material mmm in mr.sharedMaterials)
{
matStr += "[" + mmm + "] ";
}
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";
}
outStr += outStr2;
}
return outStr;
}
bool MaterialsAreTheSame(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
HashSet<Material> aMats = new HashSet<Material>();
for (int i = 0; i < a.materials.Length; i++) aMats.Add(a.materials[i]);
HashSet<Material> bMats = new HashSet<Material>();
for (int i = 0; i < b.materials.Length; i++) bMats.Add(b.materials[i]);
return aMats.SetEquals(bMats);
}
bool ShadersAreTheSame(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
HashSet<Shader> aMats = new HashSet<Shader>();
for (int i = 0; i < a.shaders.Length; i++) aMats.Add(a.shaders[i]);
HashSet<Shader> bMats = new HashSet<Shader>();
for (int i = 0; i < b.shaders.Length; i++) bMats.Add(b.shaders[i]);
return aMats.SetEquals(bMats);
}
public static Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> sortIntoBakeGroups3(List<GameObjectFilterInfo> gameObjects, List<GameObjectFilterInfo> objsNotAddedToBaker, IGroupByFilter[] filters, bool splitAtlasesSoMeshesFit, int atlasSize)
{
Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap = new Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>>();
List<GameObjectFilterInfo> gos = gameObjects;
if (gos.Count < 1) return gs2bakeGroupMap;
gos.Sort();
List<List<GameObjectFilterInfo>> l = null;
GameObjectFilterInfo key = gos[0];
for (int i = 0; i < gos.Count; i++)
{
GameObjectFilterInfo goaw = gos[i];
//compare with key and decide if we need a new list
for (int j = 0; j < filters.Length; j++)
{
if (filters[j] != null && filters[j].Compare(key, goaw) != 0) l = null;
}
if (l == null)
{
l = new List<List<GameObjectFilterInfo>>();
l.Add(new List<GameObjectFilterInfo>());
gs2bakeGroupMap.Add(gos[i], l);
key = gos[i];
}
l[0].Add(gos[i]);
}
//now that objects have been grouped by the sort criteria we can see how many atlases are needed
Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap2 = new Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>>();
if (splitAtlasesSoMeshesFit)
{
foreach (GameObjectFilterInfo k in gs2bakeGroupMap.Keys)
{
List<GameObjectFilterInfo> vs = gs2bakeGroupMap[k][0];
List<GameObject> objsInGroup = new List<GameObject>();
for (int i = 0; i < vs.Count; i++)
{
objsInGroup.Add(vs[i].go);
}
MB3_TextureCombiner tc = new MB3_TextureCombiner();
tc.maxAtlasSize = atlasSize;
tc.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
tc.LOG_LEVEL = MB2_LogLevel.warn;
List<AtlasPackingResult> packingResults = new List<AtlasPackingResult>();
Material tempResMat = k.materials[0]; //we don't write to the materials so can use this as the result material
MB_AtlasesAndRects tempAtlasesAndRects = new MB_AtlasesAndRects();
if (tc.CombineTexturesIntoAtlases(null, tempAtlasesAndRects, tempResMat, objsInGroup, null, new List<string>(), null, packingResults,
onlyPackRects:true, splitAtlasWhenPackingIfTooBig:false))
{
List<List<GameObjectFilterInfo>> atlasGroups = new List<List<GameObjectFilterInfo>>();
for (int i = 0; i < packingResults.Count; i++)
{
List<GameObjectFilterInfo> ngos = new List<GameObjectFilterInfo>();
List<MB_MaterialAndUVRect> matsData = (List<MB_MaterialAndUVRect>)packingResults[i].data;
for (int j = 0; j < matsData.Count; j++)
{
for (int kk = 0; kk < matsData[j].objectsThatUse.Count; kk++)
{
GameObjectFilterInfo gofi = vs.Find(x => x.go == matsData[j].objectsThatUse[kk]);
//Debug.Assert(gofi != null);
ngos.Add(gofi);
}
}
ngos[0].atlasIndex = (short)i;
atlasGroups.Add(ngos);
}
gs2bakeGroupMap2.Add(k, atlasGroups);
}
else
{
gs2bakeGroupMap2.Add(k, gs2bakeGroupMap[k]);
}
}
}
else
{
gs2bakeGroupMap2 = gs2bakeGroupMap;
}
return gs2bakeGroupMap2;
}
void createBakers(Dictionary<GameObjectFilterInfo, List<GameObjectFilterInfo>> gs2bakeGroupMap, List<GameObjectFilterInfo> objsNotAddedToBaker)
{
string s = "";
int numBakers = 0;
int numObjsAdded = 0;
if (generate_AssetsFolder == null || generate_AssetsFolder == "")
{
Debug.LogError("Need to choose a folder for saving the combined material assets.");
return;
}
List<GameObjectFilterInfo> singletonObjsNotAddedToBaker = new List<GameObjectFilterInfo>();
foreach (List<GameObjectFilterInfo> gaw in gs2bakeGroupMap.Values)
{
if (gaw.Count > 1)
{
numBakers++;
numObjsAdded += gaw.Count;
createAndSetupBaker(gaw, generate_AssetsFolder);
s += " Created meshbaker for shader=" + gaw[0].shaderName + " lightmap=" + gaw[0].lightmapIndex + " OBuvs=" + gaw[0].outOfBoundsUVs + "\n";
}
else
{
singletonObjsNotAddedToBaker.Add(gaw[0]);
}
}
s = "Created " + numBakers + " bakers. Added " + numObjsAdded + " objects\n" + s;
Debug.Log(s);
s = "Objects not added=" + objsNotAddedToBaker.Count + " objects that have unique material=" + singletonObjsNotAddedToBaker.Count + "\n";
for (int i = 0; i < objsNotAddedToBaker.Count; i++)
{
s += " " + objsNotAddedToBaker[i].go.name +
" isStatic=" + objsNotAddedToBaker[i].isStatic +
" submeshesOverlap" + objsNotAddedToBaker[i].submeshesOverlap +
" numMats=" + objsNotAddedToBaker[i].numMaterials + "\n";
}
for (int i = 0; i < singletonObjsNotAddedToBaker.Count; i++)
{
s += " " + singletonObjsNotAddedToBaker[i].go.name + " single\n";
}
Debug.Log(s);
}
void createAndSetupBaker(List<GameObjectFilterInfo> gaws, string pthRoot)
{
for (int i = gaws.Count - 1; i >= 0; i--)
{
if (gaws[i].go == null) gaws.RemoveAt(i);
}
if (gaws.Count < 1)
{
Debug.LogError("No game objects.");
return;
}
if (pthRoot == null || pthRoot == "")
{
Debug.LogError("Folder for saving created assets was not set.");
return;
}
int numVerts = 0;
for (int i = 0; i < gaws.Count; i++)
{
if (gaws[i].go != null)
{
numVerts = gaws[i].numVerts;
}
}
GameObject newMeshBaker = null;
if (numVerts >= 65535)
{
newMeshBaker = MB3_MultiMeshBakerEditor.CreateNewMeshBaker();
}
else
{
newMeshBaker = MB3_MeshBakerEditor.CreateNewMeshBaker();
}
newMeshBaker.name = ("MeshBaker-" + gaws[0].shaderName + "-LM" + gaws[0].lightmapIndex).ToString().Replace("/", "-");
MB3_TextureBaker tb = newMeshBaker.GetComponent<MB3_TextureBaker>();
MB3_MeshBakerCommon mb = tb.GetComponentInChildren<MB3_MeshBakerCommon>();
tb.GetObjectsToCombine().Clear();
for (int i = 0; i < gaws.Count; i++)
{
if (gaws[i].go != null && !tb.GetObjectsToCombine().Contains(gaws[i].go))
{
tb.GetObjectsToCombine().Add(gaws[i].go);
}
}
if (splitAtlasesSoMeshesFit)
{
tb.maxAtlasSize = atlasSize;
}
if (gaws[0].numMaterials > 1)
{
string pthMat = AssetDatabase.GenerateUniqueAssetPath(pthRoot + newMeshBaker.name + ".asset");
MB3_TextureBakerEditorInternal.CreateCombinedMaterialAssets(tb, pthMat);
tb.doMultiMaterial = true;
SerializedObject tbr = new SerializedObject(tb);
SerializedProperty resultMaterials = tbr.FindProperty("resultMaterials");
MB_TextureBakerEditorConfigureMultiMaterials.ConfigureMutiMaterialsFromObjsToCombine2(tb, resultMaterials, tbr);
}
else
{
string pthMat = AssetDatabase.GenerateUniqueAssetPath(pthRoot + newMeshBaker.name + ".asset");
MB3_TextureBakerEditorInternal.CreateCombinedMaterialAssets(tb, pthMat);
}
if (gaws[0].isMeshRenderer)
{
mb.meshCombiner.settings.renderType = MB_RenderType.meshRenderer;
}
else
{
mb.meshCombiner.settings.renderType = MB_RenderType.skinnedMeshRenderer;
}
}
void bakeAllBakersInScene()
{
MB3_MeshBakerRoot[] bakers = (MB3_MeshBakerRoot[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_MeshBakerRoot));
for (int i = 0; i < bakers.Length; i++)
{
if (bakers[i] is MB3_TextureBaker)
{
MB3_TextureBaker tb = (MB3_TextureBaker)bakers[i];
tb.CreateAtlases(updateProgressBar, true, new MB3_EditorMethods());
}
}
EditorUtility.ClearProgressBar();
}
public void updateProgressBar(string msg, float progress)
{
EditorUtility.DisplayProgressBar("Combining Meshes", msg, progress);
}
bool ValidateGroupByFields()
{
bool foundNone = false;
for (int i = 0; i < groupByFilterIdxs.Length; i++)
{
if (groupByFilterIdxs[i] == 0) foundNone = true; //zero is the none selection
if (foundNone && groupByFilterIdxs[i] != 0)
{
Debug.LogError("All non-none values must be at the top of the group by list");
return false;
}
}
for (int i = 0; i < groupByFilterIdxs.Length; i++)
{
for (int j = i + 1; j < groupByFilterIdxs.Length; j++)
{
if (groupByFilterIdxs[i] == groupByFilterIdxs[j] && groupByFilterIdxs[i] != 0)
{
Debug.LogError("Two of the group by options are the same.");
return false;
}
}
}
return true;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: b4dede5205ae9b44dbe7a898ae2d1e53
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerEditorWindowAnalyseSceneTab.cs
uploadId: 797180
@@ -0,0 +1,553 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.IO;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
using UnityEditor;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_MeshBakerGrouper))]
[CanEditMultipleObjects]
public class MB3_MeshBakerGrouperEditor : Editor
{
long lastBoundsCheckRefreshTime = 0;
static GUIContent gc_ClusterType = new GUIContent("Cluster Type", "The scene will be divided into cells. Meshes in each cell will be grouped into a single mesh baker");
static GUIContent gc_GridOrigin = new GUIContent("Origin", "The scene will be divided into cells. Meshes in each cell will be grouped into a single baker. This sets the origin for the clustering.");
static GUIContent gc_CellSize = new GUIContent("Cell Size", "The scene will be divided into a grid of cells. Meshes in each cell will be grouped into a single baker. This sets the size of the cells.");
static GUIContent gc_ClusterOnLMIndex = new GUIContent("Group By Lightmap Index", "Meshes sharing a lightmap index will be grouped together.");
static GUIContent gc_NumSegements = new GUIContent("Num Pie Segments", "Number of segments/slices in the pie.");
static GUIContent gc_PieAxis = new GUIContent("Pie Axis", "Scene will be divided into segments about this axis.");
static GUIContent gc_ClusterByLODLevel = new GUIContent("Cluster By LOD Level", "A baker will be created for each LOD level.");
static GUIContent gc_ClusterDistance = new GUIContent("Max Distance", "Source meshes closer than this value will be grouped into clusters.");
static GUIContent gc_IncludeCellsWithOnlyOneRenderer = new GUIContent("Include Cells With Only One Renderer", "There is no benefit in combining meshes with only one mesh except to adjust UVs to share an atlas.");
static GUIContent gc_Settings = new GUIContent("Use Shared Settings Asset", "Different bakers can share the same settings. If this field is None, then the settings below will be used.");
static GUIContent gc_PieRingSpacing = new GUIContent("Ring Spacing", "Pie segments will be divided into rings.");
static GUIContent gc_PieCombineAllInCenterRing = new GUIContent("Combine Center Ring Segments Together", "All segments in the centermost ring will be merged into a single segment.");
static GUIContent gc_ParentSceneObject = new GUIContent("Parent Scene Object","Must be a scene GameObject. Generated combined meshes will be children of this GameObject.");
static GUIContent gc_prefabOptions_outputFolder = new GUIContent("Prefab Output Folder", "Prefabs will be saved to this output folder.");
static GUIContent gc_prefabOptions_autoGeneratePrefabs = new GUIContent("Auto Generate Prefabs", "Configure each generated baker to use 'Bake Into Prefab' and generate a prefab in the output folder for the baker.");
static GUIContent gc_ButtonGenerateMeshBakers = new GUIContent("Generate Mesh Bakers", "Organize a TextureBakers objects to be combined into groups and generate a MeshBaker child for each group.");
static GUIContent gc_ButtonBakeAllChildMeshBakers = new GUIContent("Bake All Child MeshBakers", "Bake All Child MeshBakers of this object");
static GUIContent gc_ButtonDeleteAllChildMeshBakers = new GUIContent("Delete All Child Mesh Bakers & Combined Meshes", "Delete All Child Mesh Bakers & Combined Meshes");
private SerializedObject grouper;
private SerializedProperty clusterType, gridOrigin, cellSize, clusterOnLMIndex, numSegments, pieAxis, clusterByLODLevel,
clusterDistance, includeCellsWithOnlyOneRenderer, mbSettings, mbSettingsAsset, pieRingSpacing, pieCombineAllInCenterRing,
prefabOptions_outputFolder, prefabOptions_autoGeneratePrefabs, parentSceneObject;
private MB_MeshBakerSettingsEditor meshBakerSettingsMe;
private MB_MeshBakerSettingsEditor meshBakerSettingsExternal;
public void OnEnable()
{
lastBoundsCheckRefreshTime = 0;
this.grouper = serializedObject;
SerializedProperty d = grouper.FindProperty("data");
clusterType = grouper.FindProperty("clusterType");
includeCellsWithOnlyOneRenderer = d.FindPropertyRelative("includeCellsWithOnlyOneRenderer");
gridOrigin = d.FindPropertyRelative("origin");
cellSize = d.FindPropertyRelative("cellSize");
clusterOnLMIndex = d.FindPropertyRelative("clusterOnLMIndex");
clusterByLODLevel = d.FindPropertyRelative("clusterByLODLevel");
numSegments = d.FindPropertyRelative("pieNumSegments");
pieAxis = d.FindPropertyRelative("pieAxis");
clusterDistance = d.FindPropertyRelative("maxDistBetweenClusters");
mbSettings = grouper.FindProperty("meshBakerSettings");
mbSettingsAsset = grouper.FindProperty("meshBakerSettingsAsset");
pieRingSpacing = d.FindPropertyRelative("ringSpacing");
pieCombineAllInCenterRing = d.FindPropertyRelative("combineSegmentsInInnermostRing");
parentSceneObject = grouper.FindProperty("parentSceneObject");
prefabOptions_outputFolder = grouper.FindProperty("prefabOptions_outputFolder");
prefabOptions_autoGeneratePrefabs = grouper.FindProperty("prefabOptions_autoGeneratePrefabs");
meshBakerSettingsMe = new MB_MeshBakerSettingsEditor();
meshBakerSettingsMe.OnEnable(mbSettings);
if (mbSettingsAsset.objectReferenceValue != null)
{
meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
UnityEngine.Object targetObj;
string propertyName;
((MB3_MeshCombinerSettings)mbSettingsAsset.objectReferenceValue).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
meshBakerSettingsExternal.OnEnable(meshBakerSettings);
}
}
public void OnDisable()
{
if (meshBakerSettingsMe != null) meshBakerSettingsMe.OnDisable();
if (meshBakerSettingsExternal != null) meshBakerSettingsExternal.OnDisable();
}
public override void OnInspectorGUI()
{
grouper.Update();
DrawGrouperInspector();
if (GUILayout.Button(gc_ButtonGenerateMeshBakers))
{
for(int tIdx = 0; tIdx < targets.Length; tIdx++)
{
GenerateMeshBakersEditor(targets[tIdx]);
}
}
if (GUILayout.Button(gc_ButtonBakeAllChildMeshBakers))
{
for (int tIdx = 0; tIdx < targets.Length; tIdx++)
{
_bakeAllChildMeshBakers(targets[tIdx], ref grouper);
}
}
string buttonTextEnableRenderers = "Disable Renderers On All Child MeshBaker Source Objects";
bool enableRenderers = false;
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
MB3_MeshBakerCommon bc = tbg.GetComponentInChildren<MB3_MeshBakerCommon>();
if (bc != null && bc.GetObjectsToCombine().Count > 0)
{
GameObject go = bc.GetObjectsToCombine()[0];
if (go != null && go.GetComponent<Renderer>() != null && go.GetComponent<Renderer>().enabled == false)
{
buttonTextEnableRenderers = "Enable Renderers On All Child MeshBaker Source Objects";
enableRenderers = true;
}
}
}
if (GUILayout.Button(buttonTextEnableRenderers))
{
for (int tIdx = 0; tIdx < targets.Length; tIdx++)
{
EnableDisableRenderersEditor(targets[tIdx], enableRenderers);
}
}
if (GUILayout.Button(gc_ButtonDeleteAllChildMeshBakers))
{
if (EditorUtility.DisplayDialog("Delete Mesh Bakers", "Delete All Child Mesh Bakers?", "OK", "Cancel"))
{
for (int i = 0; i < targets.Length; i++)
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)targets[i];
tbg.DeleteAllChildMeshBakers();
}
}
}
if (DateTime.UtcNow.Ticks - lastBoundsCheckRefreshTime > 10000000)
{
MB3_TextureBaker tb = ((MB3_MeshBakerGrouper)target).GetComponent<MB3_TextureBaker>();
if (tb != null)
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
List<GameObject> gos = tb.GetObjectsToCombine();
Bounds b = new Bounds(Vector3.zero, Vector3.one);
if (gos.Count > 0 && gos[0] != null && gos[0].GetComponent<Renderer>() != null)
{
b = gos[0].GetComponent<Renderer>().bounds;
}
for (int i = 0; i < gos.Count; i++)
{
if (gos[i] != null && gos[i].GetComponent<Renderer>() != null)
{
b.Encapsulate(gos[i].GetComponent<Renderer>().bounds);
}
}
tbg.sourceObjectBounds = b;
lastBoundsCheckRefreshTime = DateTime.UtcNow.Ticks;
}
}
grouper.ApplyModifiedProperties();
}
public void DrawGrouperInspector()
{
EditorGUILayout.HelpBox("This component groups meshes that are close together so they can be combined." +
" It generates multiple MB3_MeshBaker objects from the list of Objects To Be Combined in the MB3_TextureBaker component." +
" Objects that are close together will be grouped together and added to a new child MB3_MeshBaker object.\n\n" +
" TIP: Try the new agglomerative cluster type!", MessageType.Info);
if (targets.Length > 1 && clusterType.intValue == (int)MB3_MeshBakerGrouper.ClusterType.agglomerative)
{
EditorGUILayout.HelpBox("Multi-Object Editing not supported for Agglomerative cluster type." +
" Behaviour will be unpredictable.", MessageType.Error);
}
Transform pgo = (Transform)EditorGUILayout.ObjectField(gc_ParentSceneObject, parentSceneObject.objectReferenceValue, typeof(Transform), true);
if (pgo != null && MB_Utility.IsSceneInstance(pgo.gameObject))
{
parentSceneObject.objectReferenceValue = pgo;
}
else
{
parentSceneObject.objectReferenceValue = null;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(clusterType, gc_ClusterType);
if (EditorGUI.EndChangeCheck())
{
MB3_MeshBakerGrouper.ClusterType newClusterType = (MB3_MeshBakerGrouper.ClusterType)clusterType.intValue;
foreach (UnityEngine.Object selObj in targets)
{
if (selObj is MB3_MeshBakerGrouper)
{
MB3_MeshBakerGrouper selectedGrouper = (MB3_MeshBakerGrouper)selObj;
if (selectedGrouper.clusterType != newClusterType
|| selectedGrouper.grouper == null
|| selectedGrouper.grouper.GetClusterType() != newClusterType)
{
Undo.RecordObject(selectedGrouper, "Cluster Type Changed");
selectedGrouper.CreateGrouper(newClusterType);
selectedGrouper.clusterType = newClusterType;
EditorUtility.SetDirty(selectedGrouper);
}
}
}
}
// Drawing clusterType specific fields
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
MB3_TextureBaker tb = tbg.GetComponent<MB3_TextureBaker>();
// Confusion warning (don't use clusterType.enumValueIndex. It is the index in the list of display names. NOT the enum value)
if (clusterType.intValue == (int)MB3_MeshBakerGrouper.ClusterType.grid)
{
if (!(tbg.grouper is MB3_MeshBakerGrouperGrid))
{
tbg.CreateGrouper((MB3_MeshBakerGrouper.ClusterType)clusterType.intValue);
}
EditorGUILayout.PropertyField(gridOrigin, gc_GridOrigin);
EditorGUILayout.PropertyField(cellSize, gc_CellSize);
}
else if (clusterType.intValue == (int)MB3_MeshBakerGrouper.ClusterType.pie)
{
if (!(tbg.grouper is MB3_MeshBakerGrouperPie))
{
tbg.CreateGrouper((MB3_MeshBakerGrouper.ClusterType)clusterType.intValue);
}
EditorGUILayout.PropertyField(gridOrigin, gc_GridOrigin);
EditorGUILayout.PropertyField(numSegments, gc_NumSegements);
EditorGUILayout.PropertyField(pieAxis, gc_PieAxis);
EditorGUILayout.PropertyField(pieRingSpacing, gc_PieRingSpacing);
EditorGUILayout.PropertyField(pieCombineAllInCenterRing, gc_PieCombineAllInCenterRing);
}
else if (clusterType.intValue == (int)MB3_MeshBakerGrouper.ClusterType.agglomerative)
{
float dist = clusterDistance.floatValue;
float unModifiedDist = dist;
float maxDist = 100f;
float minDist = .000001f;
MB3_MeshBakerGrouperCluster cl = null;
if (tbg.grouper is MB3_MeshBakerGrouperCluster)
{
cl = (MB3_MeshBakerGrouperCluster)tbg.grouper;
}
else
{
tbg.CreateGrouper((MB3_MeshBakerGrouper.ClusterType)clusterType.intValue);
cl = (MB3_MeshBakerGrouperCluster)tbg.grouper;
}
if (tbg.data._lastMaxDistBetweenClusters != tbg.data.maxDistBetweenClusters)
{
float s, l;
((MB3_MeshBakerGrouperCluster)tbg.grouper)._BuildListOfClustersToDraw(null, out s, out l, tbg.data);
tbg.data._lastMaxDistBetweenClusters = tbg.data.maxDistBetweenClusters;
}
maxDist = tbg.data._ObjsExtents;
minDist = tbg.data._minDistBetweenClusters;
if (dist < minDist || dist > maxDist)
{
dist = Mathf.Lerp(minDist, maxDist, .5f);
}
dist = EditorGUILayout.Slider(gc_ClusterDistance, dist, minDist, maxDist);
if (dist != unModifiedDist)
{
clusterDistance.floatValue = dist;
}
string btnName = "Refresh Clusters";
if (tbg.data.cluster == null || tbg.data.cluster.clusters == null || tbg.data.cluster.clusters.Length == 0)
{
btnName = "Click To Build Clusters";
}
if (GUILayout.Button(btnName))
{
if (tbg.grouper is MB3_MeshBakerGrouperCluster)
{
MB3_MeshBakerGrouperCluster cg = (MB3_MeshBakerGrouperCluster)tbg.grouper;
if (tb != null)
{
cg.BuildClusters(tb.GetObjectsToCombine(), updateProgressBar, tbg.data);
EditorUtility.ClearProgressBar();
Repaint();
SceneView.RepaintAll();
}
}
}
}
else if (clusterType.intValue == (int)MB3_MeshBakerGrouper.ClusterType.none)
{
if (!(tbg.grouper is MB3_MeshBakerGrouperPie))
{
tbg.CreateGrouper((MB3_MeshBakerGrouper.ClusterType)clusterType.intValue);
}
}
}
EditorGUILayout.PropertyField(clusterOnLMIndex, gc_ClusterOnLMIndex);
EditorGUILayout.PropertyField(clusterByLODLevel, gc_ClusterByLODLevel);
EditorGUILayout.PropertyField(includeCellsWithOnlyOneRenderer, gc_IncludeCellsWithOnlyOneRenderer);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Prefab Output Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(prefabOptions_autoGeneratePrefabs, gc_prefabOptions_autoGeneratePrefabs);
{
EditorGUI.BeginDisabledGroup(!prefabOptions_autoGeneratePrefabs.boolValue);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(prefabOptions_outputFolder, gc_prefabOptions_outputFolder);
bool pathIsValid;
string errorMessage;
{
string path = prefabOptions_outputFolder.stringValue;
prefabOptions_outputFolder.stringValue =
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(path, out errorMessage, out pathIsValid);
Debug.Assert(errorMessage != null, "ErrorMessage should never be null");
}
if (GUILayout.Button("Browse"))
{
string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
path = MB_BatchPrefabBakerEditorFunctionsCore.ConvertFullPathToProjectRelativePath(path);
prefabOptions_outputFolder.stringValue = path;
}
EditorGUILayout.EndHorizontal();
if (prefabOptions_autoGeneratePrefabs.boolValue &&
!pathIsValid)
{
EditorGUILayout.HelpBox(errorMessage, MessageType.Error);
}
EditorGUI.EndDisabledGroup();
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Mesh Baker Settings", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("These settings will be shared by all created child MeshBaker components.", MessageType.Info);
UnityEngine.Object oldObjVal = mbSettingsAsset.objectReferenceValue;
EditorGUILayout.PropertyField(mbSettingsAsset, gc_Settings);
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
MB3_TextureBaker tb = tbg.GetComponent<MB3_TextureBaker>();
bool doingTextureArrays = false;
if (tb != null && tb.textureBakeResults != null)
doingTextureArrays = tb.textureBakeResults.resultType == MB2_TextureBakeResults.ResultType.textureArray;
if (mbSettingsAsset.objectReferenceValue == null)
{
meshBakerSettingsMe.DrawGUI(tbg.meshBakerSettings, true, doingTextureArrays);
}
else
{
if (meshBakerSettingsExternal == null || oldObjVal != mbSettingsAsset.objectReferenceValue)
{
if (meshBakerSettingsExternal == null)
meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
UnityEngine.Object targetObj;
string propertyName;
((MB3_MeshCombinerSettings)mbSettingsAsset.objectReferenceValue).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
meshBakerSettingsExternal.OnEnable(meshBakerSettings);
}
meshBakerSettingsExternal.DrawGUI(
((MB3_MeshCombinerSettings)mbSettingsAsset.objectReferenceValue).data, false, doingTextureArrays);
}
}
}
/// <summary>
/// Organize a TextureBakers objects to be combined into groups and generate a MeshBaker child for each group.
/// </summary>
public static void GenerateMeshBakersEditor(UnityEngine.Object currTarget)
{
if (currTarget is MB3_MeshBakerGrouper)
{
MB3_MeshBakerGrouper mbg = (MB3_MeshBakerGrouper)currTarget;
{
bool proceed = true;
if (mbg.prefabOptions_autoGeneratePrefabs)
{
{
string errorMessage;
bool pathIsValid;
mbg.prefabOptions_outputFolder =
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(
mbg.prefabOptions_outputFolder, out errorMessage, out pathIsValid);
if (!pathIsValid)
{
Debug.LogError(errorMessage);
Debug.LogError("If " + gc_prefabOptions_autoGeneratePrefabs.text + " is enabled, you must provide an output folder. Prefabs will be saved in this folder.");
proceed = false;
}
}
}
if (proceed)
{
List<MB3_MeshBakerCommon> newBakers = mbg.GenerateMeshBakers();
if (newBakers.Count > 0) DoGeneratePrefabsIfNecessary(mbg, newBakers);
}
}
}
else
{
Debug.LogError("Argument must be of type MeshBakerGrouper to use this function");
}
}
private static void DoGeneratePrefabsIfNecessary(MB3_MeshBakerGrouper grouper, List<MB3_MeshBakerCommon> newBakers)
{
if (!grouper.prefabOptions_autoGeneratePrefabs &&
!grouper.prefabOptions_mergeOutputIntoSinglePrefab) return;
{
string errorMessage;
bool pathIsValid;
grouper.prefabOptions_outputFolder =
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(
grouper.prefabOptions_outputFolder, out errorMessage, out pathIsValid);
if (!pathIsValid)
{
Debug.LogError(errorMessage);
return;
}
}
if (grouper.prefabOptions_autoGeneratePrefabs)
{
for (int i = 0; i < newBakers.Count; i++)
{
MB3_MeshBakerCommon baker = newBakers[i];
string path = grouper.prefabOptions_outputFolder;
// Generate a new prefab name
string prefabName = baker.name.Replace("MeshBaker", "CombinedMesh");
prefabName = prefabName.Replace(" ", "_");
prefabName = prefabName.Replace(",", "_");
prefabName = prefabName.Trim(Path.GetInvalidFileNameChars());
prefabName = prefabName.Trim(Path.GetInvalidPathChars());
string pathName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + prefabName + ".prefab");
if (pathName == null || pathName.Length == 0)
{
Debug.LogError("Could not generate prefab " + prefabName + " in folder " + path + ". There is something wrong with the path or prefab name.");
continue;
}
// Generate a new prefab
GameObject go = new GameObject(baker.name);
GameObject pf = MBVersionEditor.PrefabUtility_CreatePrefab(pathName, go);
// Configure the baker to bake into the prefab
baker.resultPrefab = pf;
baker.resultPrefabLeaveInstanceInSceneAfterBake = true;
baker.meshCombiner.outputOption = MB2_OutputOptions.bakeIntoPrefab;
MB_Utility.Destroy(go);
}
}
}
private static void _bakeAllChildMeshBakers(UnityEngine.Object target, ref SerializedObject grouper)
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
try
{
Transform parent = tbg.parentSceneObject;
MB3_MeshBakerCommon[] mBakers = tbg.GetComponentsInChildren<MB3_MeshBakerCommon>();
for (int i = 0; i < mBakers.Length; i++)
{
bool createdDummyMaterialBakeResult;
if (parent != null)
{
mBakers[i].parentSceneObject = parent;
}
if (grouper.targetObject == tbg)
{
MB3_MeshBakerEditorFunctions.BakeIntoCombined(mBakers[i], out createdDummyMaterialBakeResult, ref grouper);
}
else
{
MB3_MeshBakerEditorFunctions.BakeIntoCombined(mBakers[i], out createdDummyMaterialBakeResult);
}
}
}
catch (Exception ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
}
finally
{
EditorUtility.ClearProgressBar();
}
}
/// <summary>
/// Enables/Disables the renderers on the source objects
/// </summary>
public static void EnableDisableRenderersEditor(UnityEngine.Object target, bool enableRenderers)
{
MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
try
{
MB3_MeshBakerCommon[] mBakers = tbg.GetComponentsInChildren<MB3_MeshBakerCommon>();
for (int i = 0; i < mBakers.Length; i++)
{
mBakers[i].EnableDisableSourceObjectRenderers(enableRenderers);
}
}
catch (Exception ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
}
finally
{
EditorUtility.ClearProgressBar();
}
}
public bool updateProgressBar(string msg, float progress)
{
//EditorUtility.DisplayProgressBar("Creating Clusters", msg, progress);
return EditorUtility.DisplayCancelableProgressBar("Creating Clusters", msg, progress);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 8627c7a515355354798d5990a965619e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerGrouperEditor.cs
uploadId: 797180
@@ -0,0 +1,44 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
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;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_MeshCombinerSettings))]
public class MB3_MeshBakerSettingsAssetEditor : Editor
{
private SerializedObject settingsSerializedObj;
private SerializedProperty mbSettings;
private MB_MeshBakerSettingsEditor meshBakerSettingsEditor;
public void OnEnable()
{
settingsSerializedObj = new SerializedObject(target);
mbSettings = settingsSerializedObj.FindProperty("data");
meshBakerSettingsEditor = new MB_MeshBakerSettingsEditor();
meshBakerSettingsEditor.OnEnable(mbSettings);
}
public override void OnInspectorGUI()
{
MB3_MeshCombinerSettings tbg = (MB3_MeshCombinerSettings)target;
settingsSerializedObj.Update();
EditorGUILayout.HelpBox("This asset can be shared by many Mesh Bakers and MultiMeshBakers. Drag this " +
" asset to the 'Use Shared Settings' field of any Mesh Baker", MessageType.Info);
meshBakerSettingsEditor.DrawGUI(tbg.data, true, false);
settingsSerializedObj.ApplyModifiedProperties();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: b79b3cba502aa134ca22cc156985b07e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerSettingsAssetEditor.cs
uploadId: 797180
@@ -0,0 +1,231 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
using UnityEditor;
namespace DigitalOpus.MB.MBEditor
{
public class MB_MeshBakerSettingsEditor
{
private static GUIContent
gc_renderTypeGUIContent = new GUIContent("Renderer", "The type of renderer to add to the combined mesh."),
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.\n\n" +
"generate new UV Layout: Use this if you want to bake a lightmap after the combined mesh has been generated\n\n" +
"copy UV2 unchanged: Use this if UV2 is being used for something other than lightmaping.\n\n" +
"ignore UV2: A UV2 channel will not be generated for the combined mesh\n\n" +
"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"),
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."),
gc_doNormGUIContent = new GUIContent("Include Normals"),
gc_doTanGUIContent = new GUIContent("Include Tangents"),
gc_doColGUIContent = new GUIContent("Include Colors"),
gc_doBlendShapeGUIContent = new GUIContent("Include Blend Shapes"),
gc_doUVGUIContent = new GUIContent("Include UV"),
gc_doUV3GUIContent = new GUIContent("Include UV3"),
gc_doUV4GUIContent = new GUIContent("Include UV4"),
gc_doUV5GUIContent = new GUIContent("Include UV5"),
gc_doUV6GUIContent = new GUIContent("Include UV6"),
gc_doUV7GUIContent = new GUIContent("Include UV7"),
gc_doUV8GUIContent = new GUIContent("Include UV8"),
gc_uv2HardAngleGUIContent = new GUIContent(" UV2 Hard Angle", "Angles greater than 'hard angle' in degrees will be split."),
gc_uv2PackingMarginUV3GUIContent = new GUIContent(" UV2 Packing Margin", "The margin between islands in the UV layout measured in UV coordinates (0..1) not pixels"),
gc_PivotLocationType = new GUIContent("Pivot Location Type", "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."),
gc_PivotLocation = new GUIContent("Pivot Location"),
gc_OptimizeAfterBake = new GUIContent("Optimize After Bake", "This does the same thing that 'Optimize' does on the ModelImporter."),
gc_AssignMeshCusomizer = new GUIContent("Assign To Mesh Customizer", "This is a custom script that can be used to alter data just before channels are assigned to the mesh." +
" It could be used for example to inject a Texture Array slice index into mesh coordinate (uv.z or colors.a)."),
gc_smrNoExtraBonesWhenCombiningMeshRenderers = new GUIContent("No Extra Bones For Mesh Renderers", "If a MeshRenderer is a child of another bone in the hierarchy (e.g. a sword is a child of a hand bone), then the MeshRenderer's vertices " +
" will be merged with the parent bone's vertices eliminating the extra bone (the sword becomes part of the hand). This reduces the bone count, but the MeshRenderer can never be moved independently of its parent.\n\n" +
"If you want some bones merged and some bones Independent, then move the 'Independent' bones in the hierarchy so that they are not descendants of other bones before baking. They can be re-parented after baking."),
gc_smrMergeBlendShapesWithSameNames = new GUIContent("Merge Blend Shapes With Same Names", "Enable this if you are combining multiple skinned meshes on a single rig (mixing and matching different body part variations and clothes) and the body parts have the " +
" same blend shape names. The combined mesh will preserve the original blend shape names. All blend shapes with the same name will activate in lockstep\n\n" +
"Disable this if you are combining multiple characters into a single combined skinned mesh and want to be able to activate the blend shapes on the different characters independently. " +
" the blend shapes will be re-named. Use the MB_BlendShape2CombinedMap component to control which blend shape activate."),
gc_meshAPItoUse = new GUIContent("Mesh API",
"Unity provides two APIs for baking meshes.\n\n" +
" Simple API: This is an older simpler API for meshes. This is the only API available before Unity 2020.2. In most cases it is slower, but is slightly faster for baking skinned meshes and Show-Hide operations.\n\n" +
" Native Array API (beta): This is a newer, usually faster API that uses NativeArrays. The Unity version must be 2020.2 or newer to use this. In most cases it is faster, but can be slower when baking skinned meshes. It should become faster in the future as most enhancements will happen with this API."
);
private SerializedProperty doNorm, doTan, doUV, doUV3, doUV4, doUV5, doUV6, doUV7, doUV8, doCol,
doBlendShapes, lightmappingOption, renderType, clearBuffersAfterBake,
uv2OutputParamsPackingMargin, uv2OutputParamsHardAngle, pivotLocationType,
pivotLocation, optimizeAfterBake, assignToMeshCustomizer,
meshAPItoUse;
private SerializedProperty smrNoExtraBonesWhenCombiningMeshRenderers, smrMergeBlendShapesWithSameNames;
private MB_EditorStyles editorStyles = new MB_EditorStyles();
/// <summary>
/// This is the regular init method that should usually be used
/// </summary>
/// <param name="meshBakerSettingsData">Should be the MB_IMeshBakerSettingsData implementor</param>
public void OnEnable(SerializedProperty meshBakerSettingsData)
{
_InitCommon(meshBakerSettingsData);
}
public void OnDisable()
{
editorStyles.DestroyTextures();
}
private void _InitCommon(SerializedProperty combiner)
{
renderType = combiner.FindPropertyRelative("_renderType");
lightmappingOption = combiner.FindPropertyRelative("_lightmapOption");
doNorm = combiner.FindPropertyRelative("_doNorm");
doTan = combiner.FindPropertyRelative("_doTan");
doUV = combiner.FindPropertyRelative("_doUV");
doUV3 = combiner.FindPropertyRelative("_doUV3");
doUV4 = combiner.FindPropertyRelative("_doUV4");
doUV5 = combiner.FindPropertyRelative("_doUV5");
doUV6 = combiner.FindPropertyRelative("_doUV6");
doUV7 = combiner.FindPropertyRelative("_doUV7");
doUV8 = combiner.FindPropertyRelative("_doUV8");
doCol = combiner.FindPropertyRelative("_doCol");
doBlendShapes = combiner.FindPropertyRelative("_doBlendShapes");
uv2OutputParamsPackingMargin = combiner.FindPropertyRelative("_uv2UnwrappingParamsPackMargin");
uv2OutputParamsHardAngle = combiner.FindPropertyRelative("_uv2UnwrappingParamsHardAngle");
pivotLocationType = combiner.FindPropertyRelative("_pivotLocationType");
pivotLocation = combiner.FindPropertyRelative("_pivotLocation");
optimizeAfterBake = combiner.FindPropertyRelative("_optimizeAfterBake");
assignToMeshCustomizer = combiner.FindPropertyRelative("_assignToMeshCustomizer");
smrNoExtraBonesWhenCombiningMeshRenderers = combiner.FindPropertyRelative("_smrNoExtraBonesWhenCombiningMeshRenderers");
smrMergeBlendShapesWithSameNames = combiner.FindPropertyRelative("_smrMergeBlendShapesWithSameNames");
clearBuffersAfterBake = combiner.FindPropertyRelative("_clearBuffersAfterBake");
meshAPItoUse = combiner.FindPropertyRelative("_meshAPItoUse");
editorStyles.Init();
}
public void DrawGUI(MB_IMeshBakerSettings momm, bool settingsEnabled, bool doingTextureArrays)
{
EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
GUI.enabled = settingsEnabled;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(doNorm, gc_doNormGUIContent);
EditorGUILayout.PropertyField(doTan, gc_doTanGUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(doUV, gc_doUVGUIContent);
EditorGUILayout.PropertyField(doUV3, gc_doUV3GUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(doUV4, gc_doUV4GUIContent);
EditorGUILayout.PropertyField(doUV5, gc_doUV5GUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(doUV6, gc_doUV6GUIContent);
EditorGUILayout.PropertyField(doUV7, gc_doUV7GUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(doUV8, gc_doUV8GUIContent);
EditorGUILayout.PropertyField(doCol, gc_doColGUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(doBlendShapes, gc_doBlendShapeGUIContent);
if (momm.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
{
EditorGUILayout.HelpBox("Generating new lightmap UVs can split vertices which can push the number of vertices over the 64k limit.", MessageType.Warning);
}
EditorGUILayout.PropertyField(lightmappingOption, gc_lightmappingOptionGUIContent);
if (momm.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout ||
momm.lightmapOption == MB2_LightmapOptions.copy_UV2_unchanged_to_separate_rects)
{
if (momm.lightmapOption == MB2_LightmapOptions.generate_new_UV2_layout)
{
EditorGUILayout.PropertyField(uv2OutputParamsHardAngle, gc_uv2HardAngleGUIContent);
}
EditorGUILayout.PropertyField(uv2OutputParamsPackingMargin, gc_uv2PackingMarginUV3GUIContent);
EditorGUILayout.Separator();
}
UnityEngine.Object obj = null;
obj = assignToMeshCustomizer.objectReferenceValue;
EditorGUILayout.PropertyField(renderType, gc_renderTypeGUIContent);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(clearBuffersAfterBake, gc_clearBuffersAfterBakeGUIContent);
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(pivotLocationType, gc_PivotLocationType);
// Confusion warning (don't use pivotLocationType.enumValueIndex. It is the index in the list of display names. NOT the enum value)
if (pivotLocationType.intValue == (int) MB_MeshPivotLocation.customLocation)
{
EditorGUILayout.PropertyField(pivotLocation, gc_PivotLocation);
}
EditorGUILayout.PropertyField(optimizeAfterBake, gc_OptimizeAfterBake);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Skinned Mesh Renderer Settings", EditorStyles.boldLabel);
EditorGUI.BeginDisabledGroup((MB_RenderType)renderType.intValue != MB_RenderType.skinnedMeshRenderer);
EditorGUILayout.PropertyField(smrNoExtraBonesWhenCombiningMeshRenderers, gc_smrNoExtraBonesWhenCombiningMeshRenderers);
EditorGUILayout.PropertyField(smrMergeBlendShapesWithSameNames, gc_smrMergeBlendShapesWithSameNames);
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
EditorGUILayout.LabelField("Advanced Settings", EditorStyles.boldLabel);
// Don't use a PropertyField because we may not be able to use the assigned object. It may not implement requried interface.
if (doingTextureArrays)
{
bool useNewNativeArrayAPI = meshAPItoUse.intValue == (int) MB_MeshCombineAPIType.betaNativeArrayAPI;
string error = null;
if (assignToMeshCustomizer.objectReferenceValue == null)
{
error = "The Textures were baked into Texture Arrays. You probaly need to a customizer here" +
" to embed the slice index in the mesh. You can use one of the included customizers or write your own. " +
"See the example customizers in MeshBaker/Scripts/AssignToMeshCustomizers.";
} else if (useNewNativeArrayAPI && !(assignToMeshCustomizer.objectReferenceValue is IAssignToMeshCustomizer_NativeArrays))
{
error = "This Mesh Baker is configured to use Unity's new NativeArray API. This AssignToMeshCustomizer works with Unity's " +
"old API. You need an AssignToMeshCustomizer that implements IAssignToMeshCustomizer_NativeArrays. " +
"See the example customizers in MeshBaker/Scripts/AssignToMeshCustomizers.";
} else if (!useNewNativeArrayAPI && !(assignToMeshCustomizer.objectReferenceValue is IAssignToMeshCustomizer_SimpleAPI))
{
error = "This Mesh Baker is configured to use Unity's old Mesh API. This AssignToMeshCustomizer works with Unity's " +
"new NativeArray API. You need an AssignToMeshCustomizer that implements IAssignToMeshCustomizer. " +
"See the example customizers in MeshBaker/Scripts/AssignToMeshCustomizers.";
}
if (error != null)
{
EditorGUILayout.HelpBox(error, MessageType.Error);
}
}
obj = EditorGUILayout.ObjectField(gc_AssignMeshCusomizer, obj, typeof(UnityEngine.Object), true);
if (obj == null || !(obj is IAssignToMeshCustomizer))
{
assignToMeshCustomizer.objectReferenceValue = null;
}
else
{
assignToMeshCustomizer.objectReferenceValue = obj;
}
EditorGUILayout.PropertyField(meshAPItoUse, gc_meshAPItoUse);
GUI.enabled = true;
EditorGUILayout.EndVertical();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 82ca664c08ee65a42938adb59475f380
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MeshBakerSettingsEditor.cs
uploadId: 797180
@@ -0,0 +1,78 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_MultiMeshBaker))]
[CanEditMultipleObjects]
public class MB3_MultiMeshBakerEditor : Editor
{
MB3_MeshBakerEditorInternal mbe = new MB3_MeshBakerEditorInternal();
[MenuItem(@"GameObject/Create Other/Mesh Baker/TextureBaker and MultiMeshBaker", false, 100)]
public static GameObject CreateNewMeshBaker()
{
MB3_TextureBaker[] mbs = (MB3_TextureBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_TextureBaker));
Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
int largest = 0;
try
{
for (int i = 0; i < mbs.Length; i++)
{
Match match = regex.Match(mbs[i].name);
if (match.Success)
{
int val = Convert.ToInt32(match.Groups[1].Value);
if (val >= largest)
largest = val + 1;
}
}
}
catch (Exception ex)
{
if (ex == null) ex = null; //Do nothing supress compiler warning
}
GameObject nmb = new GameObject("TextureBaker (" + largest + ")");
nmb.transform.position = Vector3.zero;
MB3_TextureBaker tb = nmb.AddComponent<MB3_TextureBaker>();
tb.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
MB3_MeshBakerGrouper mbg = nmb.AddComponent<MB3_MeshBakerGrouper>();
GameObject meshBaker = new GameObject("MultiMeshBaker");
MB3_MultiMeshBaker mmb = meshBaker.AddComponent<MB3_MultiMeshBaker>();
mmb.meshCombiner.settingsHolder = mbg;
meshBaker.transform.parent = nmb.transform;
return nmb;
}
void OnEnable()
{
mbe.OnEnable(serializedObject);
}
void OnDisable()
{
mbe.OnDisable();
}
public override void OnInspectorGUI()
{
mbe.OnInspectorGUI(serializedObject, (MB3_MeshBakerCommon)target, targets, typeof(MB3_MeshBakerEditorWindow));
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: e5238fa3cc273c740a7860c0aadcacf2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_MultiMeshBakerEditor.cs
uploadId: 797180
@@ -0,0 +1,365 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
using System.Text;
using System.Linq;
using static DigitalOpus.MB.MBEditor.GameObjectFilterInfo;
namespace DigitalOpus.MB.MBEditor
{
public interface IGroupByFilter
{
/// <summary>
/// this name appears in the dropdown list.
/// </summary>
/// <returns>The name.</returns>
string GetName();
/// <summary>
/// returns a description of the game object for this filter
/// eg. renderType=MeshFilter
/// </summary>
/// <returns>The description.</returns>
/// <param name="fi">Fi.</param>
string GetDescription(GameObjectFilterInfo fi);
/// <summary>
/// For sorting Similar to IComparer.Compare
/// </summary>
int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b);
}
[Serializable]
public class GameObjectFilterInfo : IComparable
{
public enum TransparentOrOpaque
{
NotApplicable = -1,
Opaque = 0,
Cutout = 1,
Fade = 2,
Transparent = 3,
}
public enum URPBlendMode // called SurfaceType in URP
{
Opaque = 0,
Transparent = 1
}
public enum HDRPBlendMode // called SurfaceType in HDRP
{
Opaque = 0,
Transparent = 1
}
public int[] URPBlendMode_2_StandardBlendMode = new int[]
{
(int) TransparentOrOpaque.Opaque,
(int) TransparentOrOpaque.Transparent
};
public int[] HDRPBlendMode_2_StandardBlendMode = new int[]
{
(int) TransparentOrOpaque.Opaque,
(int) TransparentOrOpaque.Transparent
};
public enum MetallicOrSpecular
{
NotApplicable = -1,
Specular = 0,
Metallic = 1
}
public GameObject go;
public string shaderName = "";
public Shader[] shaders = null; //distinct set of shaders used
public string materialName = "";
public Material[] materials = null; //disinct set of materials used
public string standardShaderBlendModesName = "";
public string metallicOrSpecularName = "";
public TransparentOrOpaque[] transparencies = null;
public MetallicOrSpecular[] metallicOrSpeculars = null;
public bool outOfBoundsUVs = false;
public bool submeshesOverlap = false;
public bool alreadyInBakerList = false;
public string setOfMaps;
public int numMaterials = 1;
public int lightmapIndex = -1;
public int layerIndex = -1;
public int numVerts = 0;
public bool isStatic = false;
public bool isMeshRenderer = true;
public StringBuilder warning = new StringBuilder();
public short atlasIndex = 0;
IGroupByFilter[] filters;
public int CompareTo(System.Object obj)
{
if (obj is GameObjectFilterInfo)
{
GameObjectFilterInfo gobj = (GameObjectFilterInfo)obj;
int gb;
for (int i = 0; i < filters.Length; i++)
{
if (filters[i] != null)
{
gb = filters[i].Compare(this, gobj);
if (gb != 0) return gb;
}
}
}
return 0;
}
public GameObjectFilterInfo(GameObject g, HashSet<GameObject> objsAlreadyInBakers, IGroupByFilter[] filts)
{
go = g;
Renderer r = MB_Utility.GetRenderer(g);
//material = r.sharedMaterial;
//if (material != null) shader = material.shader;
HashSet<Material> matsSet = new HashSet<Material>();
HashSet<Shader> shaderSet = new HashSet<Shader>();
if (r is SkinnedMeshRenderer) isMeshRenderer = false;
else isMeshRenderer = true;
materials = r.sharedMaterials;
//shaders = new Shader[materials.Length];
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
{
matsSet.Add(materials[i]);
shaderSet.Add(materials[i].shader);
}
}
materials = new Material[matsSet.Count];
matsSet.CopyTo(materials);
shaders = new Shader[shaderSet.Count];
transparencies = new TransparentOrOpaque[matsSet.Count];
metallicOrSpeculars = new MetallicOrSpecular[matsSet.Count];
shaderSet.CopyTo(shaders);
Array.Sort(materials, new NameComparer());
Array.Sort(shaders, new NameComparer());
List<string> standardShaderBlendModesNameSet = new List<string>();
List<string> metallicSpecularNameSet = new List<string>();
for (int i = 0; i < materials.Length; i++)
{
{
if (materials[i].renderQueue > (int)UnityEngine.Rendering.RenderQueue.GeometryLast)
{
transparencies[i] = TransparentOrOpaque.Transparent;
}
else
{
transparencies[i] = TransparentOrOpaque.Opaque;
}
}
if (materials[i].shader.name.StartsWith("Standard"))
{
{
if (materials[i].HasProperty("_SpecGlossMap") || materials[i].HasProperty("_SpecColor"))
{
metallicOrSpeculars[i] = MetallicOrSpecular.Specular;
}
else
{
metallicOrSpeculars[i] = MetallicOrSpecular.Metallic;
}
}
}
else if (materials[i].shader.name.StartsWith("Universal Render Pipeline") && materials[i].HasProperty("_Surface"))
{
{
// Check URP blend mode (opaque, transparent)
int surfaceMode = (int)materials[i].GetFloat("_Surface");
if (surfaceMode < 0 || surfaceMode > (int)URPBlendMode.Transparent)
{
Debug.LogError("Unsupported surface mode, were more surface modes added to the URP?");
surfaceMode = Mathf.Clamp(surfaceMode, (int)URPBlendMode.Opaque, (int)URPBlendMode.Transparent);
}
}
{
// Check URP workflow (specular, transparent)
if (materials[i].HasProperty("_WorkflowMode"))
{
if (materials[i].GetFloat("_WorkflowMode") == (int)MetallicOrSpecular.Specular)
{
metallicOrSpeculars[i] = MetallicOrSpecular.Specular;
}
else
{
metallicOrSpeculars[i] = MetallicOrSpecular.Metallic;
}
}
else if (materials[i].HasProperty("_Metallic"))
{
metallicOrSpeculars[i] = MetallicOrSpecular.Metallic;
}
else
{
metallicOrSpeculars[i] = MetallicOrSpecular.NotApplicable;
}
}
}
else if (materials[i].shader.name.StartsWith("HDRP") && materials[i].HasProperty("_SurfaceType"))
{
int surfaceMode = (int)materials[i].GetFloat("_SurfaceType");
if (surfaceMode < 0 || surfaceMode > (int)HDRPBlendMode.Transparent)
{
Debug.LogError("Unsupported surface mode, were more surface modes added to the HDRP?");
surfaceMode = Mathf.Clamp(surfaceMode, (int)HDRPBlendMode.Opaque, (int)HDRPBlendMode.Transparent);
}
metallicOrSpeculars[i] = MetallicOrSpecular.Metallic; // HDRP is always metallic
}
else
{
metallicOrSpeculars[i] = MetallicOrSpecular.NotApplicable;
}
if (!standardShaderBlendModesNameSet.Contains(transparencies[i].ToString()))
{
standardShaderBlendModesNameSet.Add(transparencies[i].ToString());
}
if (!metallicSpecularNameSet.Contains(metallicOrSpeculars[i].ToString()))
{
metallicSpecularNameSet.Add(metallicOrSpeculars[i].ToString());
}
materialName += (materials[i] == null ? "null" : materials[i].name);
if (i < materials.Length - 1) materialName += ",";
}
standardShaderBlendModesName = "";
standardShaderBlendModesNameSet.Sort();
foreach (string modeName in standardShaderBlendModesNameSet)
{
standardShaderBlendModesName += modeName + ",";
}
metallicOrSpecularName = "";
metallicSpecularNameSet.Sort();
foreach (string permutationName in metallicSpecularNameSet)
{
metallicOrSpecularName += permutationName + ",";
}
for (int i = 0; i < shaders.Length; i++)
{
shaderName += (shaders[i] == null ? "null" : shaders[i].name);
if (i < shaders.Length - 1) shaderName += ",";
}
{
List<string> listOfMaps = new List<string>();
for (int i = 0; i < materials.Length; i++)
{
listOfMaps.Clear();
List<ShaderTextureProperty> texPropertyNamesList = new List<ShaderTextureProperty>();
List<ShaderTextureProperty> customPropNames_Unused = new List<ShaderTextureProperty>();
MBVersion.CollectPropertyNames(texPropertyNamesList,
MB3_TextureCombinerPipeline.shaderTexPropertyNames,
customPropNames_Unused,
materials[i],
MB2_LogLevel.info);
string[] propertyNames = texPropertyNamesList.Select(stp => stp.name).ToArray();
foreach (string propName in propertyNames)
{
if (listOfMaps.Contains(propName))
{
// Already added, don't add again
}
else if ( MB3_TextureCombinerPipeline.shaderTexPropertiesToExclude.Contains(propName))
{
// Don't add
}
else
{
if (materials[i].HasProperty(propName) && materials[i].GetTexture(propName) != null)
{
listOfMaps.Add(propName);
}
}
}
}
listOfMaps.Sort();
if (listOfMaps.Count == 0)
{
setOfMaps = "None";
}
else
{
setOfMaps = string.Join(", ", listOfMaps);
}
}
lightmapIndex = r.lightmapIndex;
Mesh mesh = MB_Utility.GetMesh(g);
numVerts = 0;
if (mesh != null)
{
numVerts = mesh.vertexCount;
}
isStatic = go.isStatic;
numMaterials = materials.Length;
warning = new StringBuilder();
alreadyInBakerList = objsAlreadyInBakers.Contains(g);
outOfBoundsUVs = false;
submeshesOverlap = false;
filters = filts;
layerIndex = g.layer;
}
public string GetDescription(IGroupByFilter[] groupBy, GameObjectFilterInfo fi)
{
string desc = "";
if (groupBy != null)
{
for (int i = 0; i < groupBy.Length; i++)
{
desc += groupBy[i].GetDescription(fi) + " ";
}
return desc;
}
else
{
return "todo";
}
}
private class NameComparer : Comparer<UnityEngine.Object>
{
public override int Compare(UnityEngine.Object a, UnityEngine.Object b)
{
return a.name.CompareTo(b.name);
}
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 435b539c6ab6a4346bc6c56e18046e1b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_SearchFilters.cs
uploadId: 797180
@@ -0,0 +1,41 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.IO;
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
[CustomEditor(typeof(MB3_TextureBaker))]
[CanEditMultipleObjects]
public class MB3_TextureBakerEditor : Editor
{
MB3_TextureBakerEditorInternal tbe = new MB3_TextureBakerEditorInternal();
void OnEnable()
{
tbe.OnEnable(serializedObject);
}
void OnDisable()
{
tbe.OnDisable();
}
public override void OnInspectorGUI()
{
tbe.DrawGUI(serializedObject, (MB3_TextureBaker)target, targets, typeof(MB3_MeshBakerEditorWindow));
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 26f57cf1f0be79d4f995b90509950e0f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_TextureBakerEditor.cs
uploadId: 797180
@@ -0,0 +1,605 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
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;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_TextureBakerEditorInternal
{
public static bool IsCombiningTexture
{
private set;
get;
}
public class MultiMatSubmeshInfo
{
public Shader shader;
public GameObjectFilterInfo.TransparentOrOpaque stdBlendMode = GameObjectFilterInfo.TransparentOrOpaque.NotApplicable;
public MultiMatSubmeshInfo(Shader s, Material m)
{
shader = s;
if (m.shader.name.StartsWith("Standard") && m.HasProperty("_Mode"))
{
stdBlendMode = (GameObjectFilterInfo.TransparentOrOpaque)m.GetFloat("_Mode");
}
else
{
stdBlendMode = GameObjectFilterInfo.TransparentOrOpaque.NotApplicable;
}
}
public override bool Equals(object obj)
{
MultiMatSubmeshInfo b = (MultiMatSubmeshInfo)obj;
return (stdBlendMode == b.stdBlendMode && shader == b.shader);
}
public override int GetHashCode()
{
return shader.GetHashCode() ^ (int)stdBlendMode;
}
}
public class MeshSubmeshMaterial
{
public Mesh mesh;
public Material srcMat;
public int submesh;
public bool obUVs;
public GameObject srcGameObj;
public MeshSubmeshMaterial(Mesh mesh, Material srcMat, int submesh, bool obUVs, GameObject srcGo)
{
this.mesh = mesh;
this.srcMat = srcMat;
this.submesh = submesh;
this.obUVs = obUVs;
this.srcGameObj = srcGo;
}
public override bool Equals(object obj)
{
var material = obj as MeshSubmeshMaterial;
return material != null &&
EqualityComparer<Mesh>.Default.Equals(mesh, material.mesh) &&
EqualityComparer<Material>.Default.Equals(srcMat, material.srcMat) &&
submesh == material.submesh &&
obUVs == material.obUVs;
}
public override int GetHashCode()
{
var hashCode = -1560254091;
hashCode = hashCode * -1521134295 + EqualityComparer<Mesh>.Default.GetHashCode(mesh);
hashCode = hashCode * -1521134295 + EqualityComparer<Material>.Default.GetHashCode(srcMat);
hashCode = hashCode * -1521134295 + submesh.GetHashCode();
hashCode = hashCode * -1521134295 + obUVs.GetHashCode();
return hashCode;
}
}
//add option to exclude skinned mesh renderer and mesh renderer in filter
//example scenes for multi material
internal static GUIContent insertContent = new GUIContent("+", "add a material");
internal static GUIContent deleteContent = new GUIContent("-", "delete a material");
internal static GUILayoutOption buttonWidth = GUILayout.MaxWidth(20f);
public static GUIContent noneContent = new GUIContent("");
//private SerializedObject textureBaker;
internal SerializedProperty logLevel, textureBakeResults, maxTilingBakeSize, maxAtlasSize,
doMultiMaterial, doMultiMaterialSplitAtlasesIfTooBig, doMultiMaterialIfOBUVs, considerMeshUVs, resultMaterial, resultMaterials, atlasPadding,
resizePowerOfTwoTextures, customShaderProperties, texturePropNamesToIgnore, objsToMesh, texturePackingAlgorithm, layerTexturePackerFastMesh, maxAtlasWidthOverride, maxAtlasHeightOverride, useMaxAtlasWidthOverride, useMaxAtlasHeightOverride,
forcePowerOfTwoAtlas, considerNonTextureProperties, sortOrderAxis, resultType,
resultMaterialsTexArray, textureArrayOutputFormats;
internal bool resultMaterialsFoldout = true;
internal bool showInstructions = false;
internal bool showContainsReport = true;
private int objsToBeCombined_CurrentPage = 1;
private int objsToBecombined_NumPerPage = 50;
internal MB_EditorStyles editorStyles = new MB_EditorStyles();
Color buttonColor = new Color(.8f, .8f, 1f, 1f);
internal static GUIContent
createPrefabAndMaterialLabelContent = new GUIContent("Create Empty Assets For Combined Material", "Creates a material asset and a 'MB2_TextureBakeResult' asset. You should set the shader on the material. Mesh Baker uses the Texture properties on the material to decide what atlases need to be created. The MB2_TextureBakeResult asset should be used in the 'Texture Bake Result' field."),
logLevelContent = new GUIContent("Log Level"),
openToolsWindowLabelContent = new GUIContent("Open Tools For Adding Objects", "Use these tools to find out what can be combined, discover possible problems with meshes, and quickly add objects."),
fixOutOfBoundsGUIContent = new GUIContent("Consider Mesh UVs", "Textures copied to the atlas will be clipped to the mesh UV rectangle as well as the texture material tiling. This can have two effects:\n\n" +
"1) If the mesh only uses a small rectangle of it's source texture (atlas) then only that small rectangle will be copied to the atlas.\n\n" +
"2) If the mesh has uvs outside the 0,1 range (tiling) then this tiling will be copied to the atlas."),
resizePowerOfTwoGUIContent = new GUIContent("Resize Power-Of-Two Textures", "Shrinks textures so they have a clear border of width 'Atlas Padding' around them. Improves texture packing efficiency."),
customShaderPropertyNamesGUIContent = new GUIContent("Custom Shader Property Names", "Mesh Baker has a list of common texture properties that it looks for in shaders to generate atlases. Custom shaders may have texture properties not on this list. Add them here and Mesh Baker will generate atlases for them."),
gc_texturePropNamesToIgnore = new GUIContent("Texture Properties To Ignore", "A list of material texture properties to ignore. Atlases will not be generated for these properties. Some materials have textures that are not positioned on the mesh using UV coordinates (for example cell shader color ramps or LUTs). Usually atlases should not be created for these properties."),
combinedMaterialsGUIContent = new GUIContent("Combined Materials", "Use the +/- buttons to add multiple combined materials. You will also need to specify which materials on the source objects map to each combined material."),
textureArrayCombinedMaterialFoldoutGUIContent = new GUIContent("Texture Array Combined Materials", "Use the +/- buttons to add texture array materials. You will also need to specify which materials on the source objects map to each texture array slice."),
maxTilingBakeSizeGUIContent = new GUIContent("Max Tiling Bake Size", "This is the maximum size tiling textures will be baked to."),
maxAtlasSizeGUIContent = new GUIContent("Max Atlas Size", "This is the maximum size of the atlas. If the atlas is larger than this, textures being added will be shrunk."),
objectsToCombineGUIContent = new GUIContent("Objects To Be Combined", "These can be prefabs or scene objects. They must be game objects with Renderer components, not the parent objects. Materials on these objects will baked into the combined material(s)"),
textureBakeResultsGUIContent = new GUIContent("Texture Bake Result", "This asset contains a mapping of materials to UV rectangles in the atlases. It is needed to create combined meshes or adjust meshes so they can use the combined material(s). Create it using 'Create Empty Assets For Combined Material'. Drag it to the 'Texture Bake Result' field to use it."),
texturePackingAgorithmGUIContent = new GUIContent("Texture Packer", "Unity's PackTextures: Atlases are always a power of two. Can crash when trying to generate large atlases. \n\n" +
"Mesh Baker Texture Packer: Atlases will be most efficient size and shape (not limited to a power of two). More robust for large atlases. \n\n" +
"Mesh Baker Texture Packer Fast: Same as Mesh Baker Texture Packer but creates atlases on the graphics card using RenderTextures instead of the CPU. Source textures can be compressed. May not be pixel perfect. \n\n" +
"Mesh Baker Texture Packer Horizontal (Experimental): Packs all images vertically to allow horizontal-only UV-tiling.\n\n" +
"Mesh Baker Texture Packer Vertical (Experimental): Packs all images horizontally other to allow vertical-only UV-tiling.\n\n" +
"Mesh Baker Texture Packer Fast V2 (Experimental): A rewrite of 'Mesh Baker Texture Packer Fast' that is compatible with URP and HDRP and even faster.\n\n"),
layerTexturePackerFastMeshGUIContent = new GUIContent("Atlas Render Layer", "Bad 'Atlas Render Layer' value. The atlas is rendered using a MeshRenderer in the scene. This MeshRenderer needs to be on a layer that is not used by any other renderers. If there are other renderers on this layer, those renderers could render in front of the atlas, which would ruin it."),
configAtlasMultiMatsFromObjsContent = new GUIContent("Build Source To Combined Mapping From \n Objects To Be Combined", "This will group the materials on your source objects by shader and create one source to combined mapping for each shader found. For example if combining trees, then all the materials with the same bark shader will be grouped togther and all the materials with the same leaf material will be grouped together. You can adjust the results afterwards. \n\nIf Consider Mesh UVs is NOT checked, then submeshes with UVs outside 0,0..1,1 will be mapped to their own submesh regardless of shader."),
configAtlasTextureSlicesFromObjsContent = new GUIContent("Build Texture Array Slices From \n Objects To Be Combined", "This will group the materials on your source objects by shader and create slices. Objects with out-of-bounds UVs will be put on their own slice. You can adjust the results afterwards."),
forcePowerOfTwoAtlasContent = new GUIContent("Force Power-Of-Two Atlas", "Forces atlas x and y dimensions to be powers of two with aspect ratio 1:1,1:2 or 2:1. Unity recommends textures be a power of two for everything but GUI textures."),
considerNonTexturePropertiesContent = new GUIContent("Blend Non-Texture Properties", "Will blend non-texture properties such as _Color, _Glossiness with the textures. Objects with different non-texture property values will be copied into different parts of the atlas even if they use the same textures. This feature requires that TextureBlenders " +
"exist for the result material shader. It is easy to extend Mesh Baker by writing custom TextureBlenders. Default TextureBlenders exist for: \n" +
" - Standard \n" +
" - Diffuse \n" +
" - Bump Diffuse\n"),
gc_SortAlongAxis = new GUIContent("Sort Along Axis", "Transparent materials often require that triangles be rendered far to near. Game Objects will be sorted along this axis. Triangles will be added to the combined mesh in this order."),
gc_DoMultiMaterialSplitAtlasesIfTooBig = new GUIContent("Split Atlases If Textures Don't Fit", ""),
gc_DoMultiMaterialSplitAtlasesIfOBUVs = new GUIContent("Put Meshes With Out Of Bounds UV On Submesh", ""),
gc_overrideMaxAtlasWidth = new GUIContent("Override Max Atlas Width", "Set the maximum width of the atlas to this."),
gc_overrideMaxAtlasHeight = new GUIContent("Override Max Atlas Height", "Set the maximum height of the atlas to this."),
gc_useMaxAtlasWidthOverride = new GUIContent("Use Max Width Override", "Force the atlas width to not exceed the override value"),
gc_useMaxAtlasHeightOverride = new GUIContent("Use Max Height Override", "Force the atlas width to not exceed the override value"),
gc_atlasPadding = new GUIContent("Atlas Padding", "Number of pixels to pad around the edge of the atlas.");
protected string layerTexturePackerFastMeshMessage;
[MenuItem("GameObject/Create Other/Mesh Baker/TextureBaker", false, 100)]
public static void CreateNewTextureBaker()
{
MB3_TextureBaker[] mbs = (MB3_TextureBaker[]) MBVersion.FindSceneObjectsOfType(typeof(MB3_TextureBaker));
Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
int largest = 0;
try
{
for (int i = 0; i < mbs.Length; i++)
{
Match match = regex.Match(mbs[i].name);
if (match.Success)
{
int val = Convert.ToInt32(match.Groups[1].Value);
if (val >= largest)
largest = val + 1;
}
}
}
catch (Exception ex)
{
if (ex == null) ex = null; //Do nothing supress compiler warning
}
GameObject nmb = new GameObject("TextureBaker (" + largest + ")");
nmb.transform.position = Vector3.zero;
nmb.AddComponent<MB3_MeshBakerGrouper>();
MB3_TextureBaker tb = nmb.AddComponent<MB3_TextureBaker>();
tb.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
}
void _init(SerializedObject textureBaker)
{
//textureBaker = new SerializedObject(target);
logLevel = textureBaker.FindProperty("LOG_LEVEL");
doMultiMaterial = textureBaker.FindProperty("_doMultiMaterial");
doMultiMaterialSplitAtlasesIfTooBig = textureBaker.FindProperty("_doMultiMaterialSplitAtlasesIfTooBig");
doMultiMaterialIfOBUVs = textureBaker.FindProperty("_doMultiMaterialSplitAtlasesIfOBUVs");
considerMeshUVs = textureBaker.FindProperty("_fixOutOfBoundsUVs");
resultMaterial = textureBaker.FindProperty("_resultMaterial");
resultMaterials = textureBaker.FindProperty("resultMaterials");
atlasPadding = textureBaker.FindProperty("_atlasPadding");
resizePowerOfTwoTextures = textureBaker.FindProperty("_resizePowerOfTwoTextures");
customShaderProperties = textureBaker.FindProperty("_customShaderProperties");
texturePropNamesToIgnore = textureBaker.FindProperty("_texturePropNamesToIgnore");
objsToMesh = textureBaker.FindProperty("objsToMesh");
maxTilingBakeSize = textureBaker.FindProperty("_maxTilingBakeSize");
maxAtlasSize = textureBaker.FindProperty("_maxAtlasSize");
maxAtlasWidthOverride = textureBaker.FindProperty("_maxAtlasWidthOverride");
maxAtlasHeightOverride = textureBaker.FindProperty("_maxAtlasHeightOverride");
useMaxAtlasWidthOverride = textureBaker.FindProperty("_useMaxAtlasWidthOverride");
useMaxAtlasHeightOverride = textureBaker.FindProperty("_useMaxAtlasHeightOverride");
textureBakeResults = textureBaker.FindProperty("_textureBakeResults");
texturePackingAlgorithm = textureBaker.FindProperty("_packingAlgorithm");
layerTexturePackerFastMesh = textureBaker.FindProperty("_layerTexturePackerFastMesh");
forcePowerOfTwoAtlas = textureBaker.FindProperty("_meshBakerTexturePackerForcePowerOfTwo");
considerNonTextureProperties = textureBaker.FindProperty("_considerNonTextureProperties");
sortOrderAxis = textureBaker.FindProperty("sortAxis");
resultType = textureBaker.FindProperty("_resultType");
resultMaterialsTexArray = textureBaker.FindProperty("resultMaterialsTexArray");
textureArrayOutputFormats = textureBaker.FindProperty("textureArrayOutputFormats");
}
public void OnEnable(SerializedObject textureBaker)
{
_init(textureBaker);
if (editorStyles == null) editorStyles = new MB_EditorStyles();
editorStyles.Init();
}
public void OnDisable()
{
editorStyles.DestroyTextures();
}
public void DrawGUI(SerializedObject textureBaker, MB3_TextureBaker momm, UnityEngine.Object[] targets, System.Type editorWindow)
{
if (textureBaker == null)
{
return;
}
textureBaker.Update();
showInstructions = EditorGUILayout.Foldout(showInstructions, "Instructions:");
if (showInstructions)
{
EditorGUILayout.HelpBox("1. Add scene objects or prefabs to combine. For best results these should use the same shader as Combined Mesh Material.\n\n" +
"2. Create Empty Assets for Combined Mesh Material(s)\n\n" +
"3. Check that shader on Combined Mesh Material(s) are correct.\n\n" +
"4. Bake materials into Combined Mesh Material(s).\n\n" +
"5. Look at warnings/errors in console. Decide if action needs to be taken.\n\n" +
"6. You are now ready to bake combined meshes or batch bake prefabs.", UnityEditor.MessageType.None);
}
EditorGUILayout.PropertyField(logLevel, logLevelContent);
EditorGUILayout.Separator();
// Selected objects
EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
EditorGUILayout.LabelField("Objects To Be Combined", EditorStyles.boldLabel);
if (GUILayout.Button(openToolsWindowLabelContent))
{
MB3_MeshBakerEditorWindow mmWin = (MB3_MeshBakerEditorWindow) EditorWindow.GetWindow(editorWindow);
mmWin.SetTarget((MB3_MeshBakerRoot) momm);
}
object[] objs = MB3_EditorMethods.DropZone("Drag & Drop Renderers or Parents\n" + "HERE\n" +
"to add objects to be combined", 300, 50);
MB3_EditorMethods.AddDroppedObjects(objs, momm.GetObjectsToCombine());
MB_PaginatedList.GenerateObjectsToBeCombinedList(objsToMesh, ref objsToBeCombined_CurrentPage, ref objsToBecombined_NumPerPage);
EditorGUILayout.Separator();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Select Objects In Scene"))
{
List<MB3_TextureBaker> selectedBakers = _getBakersFromTargets(targets);
List<GameObject> obsToCombine = new List<GameObject>();
foreach (MB3_TextureBaker baker in selectedBakers) obsToCombine.AddRange(baker.GetObjectsToCombine());
Selection.objects = obsToCombine.ToArray();
if (momm.GetObjectsToCombine().Count > 0)
{
SceneView.lastActiveSceneView.pivot = momm.GetObjectsToCombine()[0].transform.position;
}
}
if (GUILayout.Button(gc_SortAlongAxis))
{
MB3_MeshBakerRoot.ZSortObjects sorter = new MB3_MeshBakerRoot.ZSortObjects();
sorter.sortAxis = sortOrderAxis.vector3Value;
sorter.SortByDistanceAlongAxis(momm.GetObjectsToCombine());
}
EditorGUILayout.PropertyField(sortOrderAxis, GUIContent.none);
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
// output
EditorGUILayout.Separator();
EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(resultType);
if (GUILayout.Button(createPrefabAndMaterialLabelContent))
{
List<MB3_TextureBaker> selectedBakers = _getBakersFromTargets(targets);
string newPrefabPath = EditorUtility.SaveFilePanelInProject("Asset name", "", "asset", "Enter a name for the baked texture results");
if (newPrefabPath != null)
{
for (int i = 0; i < selectedBakers.Count; i++)
{
CreateCombinedMaterialAssets(selectedBakers[i], newPrefabPath, i == 0 ? true : false);
}
}
}
EditorGUILayout.PropertyField(textureBakeResults, textureBakeResultsGUIContent);
if (textureBakeResults.objectReferenceValue != null)
{
showContainsReport = EditorGUILayout.Foldout(showContainsReport, "Shaders & Materials Contained");
if (showContainsReport)
{
EditorGUILayout.HelpBox(((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).GetDescription(), MessageType.Info);
}
}
// Confusion warning (don't use resultType.enumValueIndex. It is the index in the list of display names. NOT the enum value)
if (resultType.intValue == (int) MB2_TextureBakeResults.ResultType.textureArray)
{
MB_TextureBakerConfigureTextureArrays.DrawTextureArrayConfiguration(momm, textureBaker, this);
}
else
{
EditorGUILayout.PropertyField(doMultiMaterial, new GUIContent("Multiple Combined Materials"));
if (momm.doMultiMaterial)
{
MB_TextureBakerEditorConfigureMultiMaterials.DrawMultipleMaterialsMappings(momm, textureBaker, this);
}
else
{
EditorGUILayout.PropertyField(resultMaterial, new GUIContent("Combined Mesh Material"));
}
}
// settings
int labelWidth = 200;
EditorGUILayout.Separator();
EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
EditorGUILayout.LabelField("Material Bake Options", EditorStyles.boldLabel);
DrawPropertyFieldWithLabelWidth(atlasPadding, gc_atlasPadding, labelWidth);
DrawPropertyFieldWithLabelWidth(maxAtlasSize, maxAtlasSizeGUIContent, labelWidth);
DrawPropertyFieldWithLabelWidth(resizePowerOfTwoTextures, resizePowerOfTwoGUIContent, labelWidth);
DrawPropertyFieldWithLabelWidth(maxTilingBakeSize, maxTilingBakeSizeGUIContent, labelWidth);
EditorGUI.BeginDisabledGroup(momm.doMultiMaterial);
DrawPropertyFieldWithLabelWidth(considerMeshUVs, fixOutOfBoundsGUIContent, labelWidth);
EditorGUI.EndDisabledGroup();
if (texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.MeshBakerTexturePacker ||
texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Fast ||
texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.MeshBakerTexturePaker_Fast_V2_Beta)
{
DrawPropertyFieldWithLabelWidth(forcePowerOfTwoAtlas, forcePowerOfTwoAtlasContent, labelWidth);
}
DrawPropertyFieldWithLabelWidth(considerNonTextureProperties, considerNonTexturePropertiesContent, labelWidth);
if (texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.UnitysPackTextures)
{
EditorGUILayout.HelpBox("Unity's texture packer has memory problems and frequently crashes the editor.", MessageType.Warning);
}
EditorGUILayout.PropertyField(texturePackingAlgorithm, texturePackingAgorithmGUIContent);
if (MB3_TextureCombinerPipeline.USE_EXPERIMENTAL_HOIZONTALVERTICAL)
{
// Confusion warning (don't use texturePackingAlgorithm.enumValueIndex. It is the index in the list of display names. NOT the enum value)
if (texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal)
{
EditorGUILayout.PropertyField(useMaxAtlasWidthOverride, gc_useMaxAtlasWidthOverride);
if (!useMaxAtlasWidthOverride.boolValue) EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(maxAtlasWidthOverride, gc_overrideMaxAtlasWidth);
if (!useMaxAtlasWidthOverride.boolValue) EditorGUI.EndDisabledGroup();
}
else if (texturePackingAlgorithm.intValue == (int)MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical)
{
EditorGUILayout.PropertyField(useMaxAtlasHeightOverride, gc_useMaxAtlasHeightOverride);
if (!useMaxAtlasHeightOverride.boolValue) EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(maxAtlasHeightOverride, gc_overrideMaxAtlasHeight);
if (!useMaxAtlasHeightOverride.boolValue) EditorGUI.EndDisabledGroup();
}
}
if (texturePackingAlgorithm.intValue == (int) MB2_PackingAlgorithmEnum.MeshBakerTexturePaker_Fast_V2_Beta)
{
// layer field
int newValueLayerTexturePackerFastMesh = EditorGUILayout.LayerField(layerTexturePackerFastMeshGUIContent, layerTexturePackerFastMesh.intValue);
bool isNewValue = newValueLayerTexturePackerFastMesh == layerTexturePackerFastMesh.intValue;
layerTexturePackerFastMesh.intValue = newValueLayerTexturePackerFastMesh;
if (isNewValue)
{
Renderer[] rs = (Renderer[]) MBVersion.FindSceneObjectsOfType(typeof(Renderer));
int numRenderersOnLayer = 0;
for (int i = 0; i < rs.Length; i++)
{
if (rs[i].gameObject.layer == newValueLayerTexturePackerFastMesh) numRenderersOnLayer++;
}
string layerName = LayerMask.LayerToName(layerTexturePackerFastMesh.intValue);
if (layerName != null && layerName.Length > 0 && numRenderersOnLayer == 0)
{
layerTexturePackerFastMeshMessage = null;
} else
{
layerTexturePackerFastMeshMessage = layerTexturePackerFastMeshGUIContent.tooltip;
}
}
string scriptDefinesErrMessage = ValidatePlayerSettingsDefineSymbols();
if (layerTexturePackerFastMesh.intValue == -1 ||
(layerTexturePackerFastMeshMessage != null && layerTexturePackerFastMeshMessage.Length > 0) ||
(scriptDefinesErrMessage != null))
{
EditorGUILayout.HelpBox(layerTexturePackerFastMeshMessage + "\n\n" + scriptDefinesErrMessage, MessageType.Error);
}
}
EditorGUILayout.PropertyField(customShaderProperties, customShaderPropertyNamesGUIContent, true);
EditorGUILayout.PropertyField(texturePropNamesToIgnore, gc_texturePropNamesToIgnore, true);
EditorGUILayout.EndVertical();
EditorGUILayout.Separator();
Color oldColor = GUI.backgroundColor;
GUI.color = buttonColor;
if (GUILayout.Button("Bake Materials Into Combined Material"))
{
IsCombiningTexture = true;
List<MB3_TextureBaker> selectedBakers = _getBakersFromTargets(targets);
foreach (MB3_TextureBaker tb in selectedBakers)
{
tb.CreateAtlases(updateProgressBar, true, new MB3_EditorMethods());
EditorUtility.ClearProgressBar();
if (tb.textureBakeResults != null) EditorUtility.SetDirty(momm.textureBakeResults);
}
IsCombiningTexture = false;
}
GUI.backgroundColor = oldColor;
textureBaker.ApplyModifiedProperties();
if (GUI.changed)
{
textureBaker.SetIsDifferentCacheDirty();
}
}
public void DrawPropertyFieldWithLabelWidth(SerializedProperty prop, GUIContent content, int labelWidth)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(content, GUILayout.Width(labelWidth));
EditorGUILayout.PropertyField(prop, noneContent);
EditorGUILayout.EndHorizontal();
}
public void updateProgressBar(string msg, float progress)
{
EditorUtility.DisplayProgressBar("Combining Meshes", msg, progress);
}
public static void CreateCombinedMaterialAssets(MB3_TextureBaker target, string pth, bool allowOverwrite=true)
{
MB3_TextureBaker mom = (MB3_TextureBaker)target;
string baseName = Path.GetFileNameWithoutExtension(pth);
if (baseName == null || baseName.Length == 0) return;
string folderPath = Path.GetDirectoryName(pth) + "/";
List<string> matNames = new List<string>();
if (mom.resultType == MB2_TextureBakeResults.ResultType.textureArray)
{
for (int i = 0; i < mom.resultMaterialsTexArray.Length; i++)
{
string nm = folderPath + baseName + "-mat" + i + ".mat";
if (!allowOverwrite) nm = AssetDatabase.GenerateUniqueAssetPath(nm);
matNames.Add(nm);
AssetDatabase.CreateAsset(new Material(Shader.Find("Diffuse")), matNames[i]);
mom.resultMaterialsTexArray[i].combinedMaterial = (Material) AssetDatabase.LoadAssetAtPath(matNames[i], typeof(Material));
}
}
else
{
if (mom.doMultiMaterial)
{
for (int i = 0; i < mom.resultMaterials.Length; i++)
{
string nm = folderPath + baseName + "-mat" + i + ".mat";
if (!allowOverwrite) nm = AssetDatabase.GenerateUniqueAssetPath(nm);
matNames.Add(nm);
AssetDatabase.CreateAsset(new Material(Shader.Find("Diffuse")), matNames[i]);
mom.resultMaterials[i].combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matNames[i], typeof(Material));
}
}
else
{
string nm = folderPath + baseName + "-mat.mat";
if (!allowOverwrite) nm = AssetDatabase.GenerateUniqueAssetPath(nm);
matNames.Add(nm);
Material newMat = null;
if (mom.GetObjectsToCombine().Count > 0 && mom.GetObjectsToCombine()[0] != null)
{
Renderer r = mom.GetObjectsToCombine()[0].GetComponent<Renderer>();
if (r == null)
{
Debug.LogWarning("Object " + mom.GetObjectsToCombine()[0] + " does not have a Renderer attached to it.");
}
else
{
if (r.sharedMaterial != null)
{
newMat = new Material(r.sharedMaterial);
//newMat.shader = r.sharedMaterial.shader;
MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, r.sharedMaterial);
}
}
}
else
{
Debug.Log("If you add objects to be combined before creating the Combined Material Assets, then Mesh Baker will create a result material that is a duplicate of the material on the first object to be combined. This saves time configuring the shader.");
}
if (newMat == null)
{
newMat = new Material(Shader.Find("Diffuse"));
}
AssetDatabase.CreateAsset(newMat, matNames[0]);
mom.resultMaterial = (Material)AssetDatabase.LoadAssetAtPath(matNames[0], typeof(Material));
}
}
//create the MB2_TextureBakeResults
string nmm = pth;
if (!allowOverwrite) nmm = AssetDatabase.GenerateUniqueAssetPath(nmm);
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<MB2_TextureBakeResults>(), nmm);
mom.textureBakeResults = (MB2_TextureBakeResults)AssetDatabase.LoadAssetAtPath(nmm, typeof(MB2_TextureBakeResults));
AssetDatabase.Refresh();
}
List<MB3_TextureBaker> _getBakersFromTargets(UnityEngine.Object[] targs)
{
List<MB3_TextureBaker> outList = new List<MB3_TextureBaker>(targs.Length);
for (int i = 0; i < targs.Length; i++)
{
outList.Add((MB3_TextureBaker) targs[i]);
}
return outList;
}
public static string ValidatePlayerSettingsDefineSymbols()
{
// Check that the needed defines exist or are present when they should not be.
MBVersion.PipelineType pipelineType = MBVersion.DetectPipeline();
BuildTargetGroup targetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
string scriptDefines = MBVersionEditor.GetScriptingDefineSymbolsFromTg(targetGroup);
string s = "";
if (pipelineType == MBVersion.PipelineType.HDRP)
{
if (!scriptDefines.Contains(MBVersion.MB_USING_HDRP))
{
s += "The GraphicsSettings -> Render Pipeline Asset is configured to use HDRP. Please add 'MB_USING_HDRP' to Player Settings -> Scripting Define Symbols for all the build platforms " +
" that you are targeting. If there are compile errors check that the MeshBakerCore.asmdef file has references for:\n\n" +
" Unity.RenderPipelines.HighDefinition.Runtime\n" +
" Unity.RenderPipelines.HighDefinition.Config.Runtime (Unity 2019.3+)\n";
}
/*
Type tp = Type.GetType("UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData");
if (tp == null)
{
s += "The class 'HDAdditionalCameraData' cannot be found by the MeshBaker assembly. Ensure that the following assemblies are referenced by the MeshBaker.asmdef file: \n" +
" Unity.RenderPipelines.HighDefinition.Runtime\n" +
" Unity.RenderPipelines.HighDefinition.Config.Runtime (Unity 2019.3+)\n\n"+
"Or download the HDRP version of the package from the asset store.";
}
*/
}
else
{
if (scriptDefines.Contains(MBVersion.MB_USING_HDRP))
{
s += "Please remove 'MB_USING_HDRP' from Player Settings -> Scripting Define Symbols for the current build platform. If this define is present there may be compile errors because Mesh Baker tries to access classes which only exist in the HDRP API.";
}
}
if (s.Length > 0)
{
return s;
}
else
{
return null;
}
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 3e6251fd17be4a142ab0827940bdba27
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB3_TextureBakerEditorInternal.cs
uploadId: 797180
@@ -0,0 +1,304 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using DigitalOpus.MB.Core;
using System.Text.RegularExpressions;
namespace DigitalOpus.MB.MBEditor
{
public static class MB_BatchPrefabBakerEditorFunctions
{
public static int EvalVersionPrefabLimit
{
get { return 5; }
}
public static void CreateEmptyOutputPrefabs(string outputFolder, MB3_BatchPrefabBaker target)
{
string errorMessage;
bool isValidPath;
MB3_MeshBakerEditorFunctionsCore.SanitizeAndMakeFullPathRelativeToAssetsFolderAndValidate(outputFolder,
out errorMessage, out isValidPath);
if (!isValidPath)
{
Debug.LogError(errorMessage);
return;
}
HashSet<GameObject> srcPrefabs = new HashSet<GameObject>();
if (outputFolder.StartsWith("Assets")) outputFolder = MB_BatchPrefabBakerEditorFunctionsCore.ConvertProjectRelativePathToFullPath(outputFolder);
int numCreated = 0;
int numSkippedSrcNull = 0;
int numSkippedSrcDuplicate = 0;
int numSkippedAlreadyExisted = 0;
MB3_BatchPrefabBaker prefabBaker = (MB3_BatchPrefabBaker)target;
for (int i = 0; i < prefabBaker.prefabRows.Length; i++)
{
if (prefabBaker.prefabRows[i].sourcePrefab != null)
{
if (srcPrefabs.Contains(prefabBaker.prefabRows[i].sourcePrefab))
{
Debug.LogError($"Skipping row {i} because the source prefab was a duplicate of a previous row.");
numSkippedSrcDuplicate++;
}
else
{
srcPrefabs.Add(prefabBaker.prefabRows[i].sourcePrefab);
if (prefabBaker.prefabRows[i].resultPrefab == null)
{
string outName = outputFolder + "/" + prefabBaker.prefabRows[i].sourcePrefab.name + ".prefab";
outName = outName.Replace(Application.dataPath, "");
outName = "Assets" + outName;
outName = AssetDatabase.GenerateUniqueAssetPath(outName);
GameObject go = new GameObject(prefabBaker.prefabRows[i].sourcePrefab.name);
prefabBaker.prefabRows[i].resultPrefab = MBVersionEditor.PrefabUtility_CreatePrefab(outName, go);
GameObject.DestroyImmediate(go);
numCreated++;
}
else
{
numSkippedAlreadyExisted++;
}
}
}
else
{
numSkippedSrcNull++;
}
}
string msg = String.Format("Created {0} prefabs. Skipped {1} because source prefab was null. Skipped {2} because source prefab was a duplicate. Skipped {3} because the result prefab was already assigned", numCreated, numSkippedSrcNull, numSkippedSrcDuplicate, numSkippedAlreadyExisted);
if (numSkippedSrcNull > 0 || numSkippedAlreadyExisted > 0)
{
Debug.LogError(msg);
}
else
{
Debug.Log(msg);
}
}
public static void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
{
MB3_TextureBaker texBaker = prefabBaker.GetComponent<MB3_TextureBaker>();
List<GameObject> newPrefabs = new List<GameObject>();
List<GameObject> gos = texBaker.GetObjectsToCombine();
for (int i = 0; i < gos.Count; i++)
{
GameObject go = (GameObject)MBVersionEditor.PrefabUtility_FindPrefabRoot(gos[i]);
UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);
if (obj != null && obj is GameObject)
{
if (!newPrefabs.Contains((GameObject)obj)) newPrefabs.Add((GameObject)obj);
}
else
{
Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
}
}
// Remove prefabs that are already in the list of batch prefab baker's prefabs.
{
List<GameObject> tmpNewPrefabs = new List<GameObject>();
for (int i = 0; i < newPrefabs.Count; i++)
{
bool found = false;
for (int j = 0; j < prefabBaker.prefabRows.Length; j++)
{
if (prefabBaker.prefabRows[j].sourcePrefab == newPrefabs[i])
{
found = true;
break;
}
}
if (!found)
{
tmpNewPrefabs.Add(newPrefabs[i]);
}
}
newPrefabs = tmpNewPrefabs;
}
List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List<MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();
if (prefabBaker.prefabRows == null) prefabBaker.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
newRows.AddRange(prefabBaker.prefabRows);
for (int i = 0; i < newPrefabs.Count; i++)
{
MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
row.sourcePrefab = newPrefabs[i];
newRows.Add(row);
}
Undo.RecordObject(prefabBaker, "Populate prefab rows");
prefabBaker.prefabRows = newRows.ToArray();
}
public static void BakePrefabs(MB3_BatchPrefabBaker pb, bool doReplaceTargetPrefab)
{
if (pb.LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Batch baking prefabs");
if (MB3_MeshCombiner.EVAL_VERSION)
{
int numPrefabsLimit = EvalVersionPrefabLimit;
if (pb.prefabRows.Length > numPrefabsLimit)
{
Debug.LogError("The free version of mesh baker is limited to batch baking " + numPrefabsLimit +
" prefabs. The full version has no limit on the number of prefabs that can be baked. Delete the extra prefab rows before baking.");
return;
}
}
if (Application.isPlaying)
{
Debug.LogError("The BatchPrefabBaker cannot be run in play mode.");
return;
}
MB3_MeshBaker mb = pb.GetComponent<MB3_MeshBaker>();
mb.UpgradeToCurrentVersionIfNecessary();
if (mb == null)
{
Debug.LogError("Prefab baker needs to be attached to a Game Object with a MB3_MeshBaker component.");
return;
}
if (mb.textureBakeResults == null)
{
Debug.LogError("Texture Bake Results is not set");
return;
}
int numResultMats = mb.textureBakeResults.NumResultMaterials();
for (int i = 0; i < numResultMats; i++)
{
if (mb.textureBakeResults.GetCombinedMaterialForSubmesh(i) == null)
{
Debug.LogError("The texture bake result had a null result material on submesh " + i + ". Try re-baking textures");
return;
}
}
if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace)
{
mb.meshCombiner.outputOption = MB2_OutputOptions.bakeMeshAssetsInPlace;
}
MB2_TextureBakeResults tbr = mb.textureBakeResults;
HashSet<Mesh> sourceMeshes = new HashSet<Mesh>();
HashSet<Mesh> allResultMeshes = new HashSet<Mesh>();
//validate prefabs
for (int i = 0; i < pb.prefabRows.Length; i++)
{
if (pb.prefabRows[i] == null || pb.prefabRows[i].sourcePrefab == null)
{
Debug.LogError("Source Prefab on row " + i + " is not set.");
return;
}
if (pb.prefabRows[i].resultPrefab == null)
{
Debug.LogError("Result Prefab on row " + i + " is not set.");
return;
}
for (int j = i + 1; j < pb.prefabRows.Length; j++)
{
if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].sourcePrefab)
{
Debug.LogError("Rows " + i + " and " + j + " contain the same source prefab");
return;
}
}
for (int j = 0; j < pb.prefabRows.Length; j++)
{
if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].resultPrefab)
{
Debug.LogError("Row " + i + " source prefab is the same as row " + j + " result prefab");
return;
}
}
if (MBVersionEditor.PrefabUtility_GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.modelPrefabAsset &&
MBVersionEditor.PrefabUtility_GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.prefabAsset)
{
Debug.LogError("Row " + i + " source prefab is not a prefab asset ");
return;
}
if (MBVersionEditor.PrefabUtility_GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.modelPrefabAsset &&
MBVersionEditor.PrefabUtility_GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.prefabAsset)
{
Debug.LogError("Row " + i + " result prefab is not a prefab asset");
return;
}
GameObject so = (GameObject)GameObject.Instantiate(pb.prefabRows[i].sourcePrefab);
GameObject ro = (GameObject)GameObject.Instantiate(pb.prefabRows[i].resultPrefab);
Renderer[] rs = (Renderer[])so.GetComponentsInChildren<Renderer>(true);
for (int j = 0; j < rs.Length; j++)
{
if (MB_BatchPrefabBakerEditorFunctionsCore.IsGoodToBake(rs[j], tbr))
{
sourceMeshes.Add(MB_Utility.GetMesh(rs[j].gameObject));
}
}
rs = ro.GetComponentsInChildren<Renderer>(true);
for (int j = 0; j < rs.Length; j++)
{
Renderer r = rs[j];
if (r is MeshRenderer || r is SkinnedMeshRenderer)
{
Mesh m = MB_Utility.GetMesh(r.gameObject);
if (m != null)
{
allResultMeshes.Add(m);
}
}
}
GameObject.DestroyImmediate(so); //todo should cache these and have a proper cleanup at end
GameObject.DestroyImmediate(ro);
}
sourceMeshes.IntersectWith(allResultMeshes);
HashSet<Mesh> sourceMeshesThatAreUsedByResult = sourceMeshes;
if (sourceMeshesThatAreUsedByResult.Count > 0)
{
foreach (Mesh m in sourceMeshesThatAreUsedByResult)
{
Debug.LogWarning("Mesh " + m + " is used by both the source and result prefabs. New meshes will be created.");
}
//return;
}
List<MB_BatchPrefabBakerEditorFunctionsCore.UnityTransform> unityTransforms = new List<MB_BatchPrefabBakerEditorFunctionsCore.UnityTransform>();
// Bake the meshes using the meshBaker component one prefab at a time
// Version check
for (int prefabIdx = 0; prefabIdx < pb.prefabRows.Length; prefabIdx++)
{
if (doReplaceTargetPrefab)
{
MB_BatchPrefabBakerEditorFunctionsCore._ProcessPrefabRowReplaceTargetPrefab(pb.LOG_LEVEL, pb.prefabRows[prefabIdx].sourcePrefab, pb.prefabRows[prefabIdx].resultPrefab, tbr, unityTransforms, (MB3_MeshCombinerSingle) mb.meshCombiner);
}
else
{
MB_BatchPrefabBakerEditorFunctionsCore._ProcessPrefabRowOnlyMeshesAndMaterials(pb.LOG_LEVEL, pb.prefabRows[prefabIdx].sourcePrefab, pb.prefabRows[prefabIdx].resultPrefab, tbr, unityTransforms, (MB3_MeshCombinerSingle) mb.meshCombiner);
}
}
AssetDatabase.Refresh();
mb.ClearMesh();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 372fcc119f8877c49b446a03f9603644
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_BatchPrefabBakerEditorFunctions.cs
uploadId: 797180
@@ -0,0 +1,23 @@
using UnityEditor;
using UnityEngine;
using DigitalOpus.MB.Core;
#if UNITY_2018_1_OR_NEWER
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace DigitalOpus.MB.MBEditor
{
class MB_BuildPreprocessChecker : IPreprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }
public void OnPreprocessBuild(BuildReport report)
{
string msg = MB3_TextureBakerEditorInternal.ValidatePlayerSettingsDefineSymbols();
if (msg != null) Debug.LogError(msg);
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 44eb70764e9827e4588ea4a1c5888b59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_BuildPreprocessChecker.cs
uploadId: 797180
@@ -0,0 +1,189 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB_ReplacePrefabsInSceneEditorWindow : EditorWindow
{
private MB_ReplacePrefabsSettings model;
private SerializedObject soModel;
private SerializedProperty prefabPairs;
private SerializedProperty reverseSrcAndTarg;
private SerializedProperty enforceSrcAndTargHaveSameStructure;
Vector2 scrollViewPos;
private string errorMessages;
private string infoMessages;
private GUIContent GUI_replacePefabsInScene = new GUIContent("Replace Prefabs In Scene", "This will find all instances of the source prefabs in the scene and replace them with instances of the target prefabs." +
"Will attempt to copy component settings from the source to the target (ignoring references to project assets, those are left alone)." +
"Prefabs should have identical hierarchy and components for the copy component settings to work.");
private GUIContent GUI_switchSrcAndTarget = new GUIContent("Switch Source and Target Prefabs", "If this is checked then search the scene for target prefabs and replace them with source prefabs.");
private GUIContent GUI_enforceSrcAndTargetHaveSameStructure = new GUIContent("Enforce Source And Target Have Same Structure", "If this is checked then prefab instances will only be replaced if they have the same hierarchy and components. \n\n" +
"If it is not checked then prefabs can be very different and ONLY THE TRANSFORM, LAYERS, TAGS & STATIC FLAGS ARE COPIED.\n\n" +
"WARNING THIS IS A DESTRUCTIVE OPERARTION! BACK UP YOUR SCENE FIRST.");
[MenuItem("Window/Mesh Baker/Replace Prefabs In Scene")]
public static void ShowWindow()
{
GetWindow<MB_ReplacePrefabsInSceneEditorWindow>(true, "Replace Prefabs In Scene", true).Show();
}
public static void ShowWindow(MB3_BatchPrefabBaker.MB3_PrefabBakerRow[] prefabPairs)
{
MB_ReplacePrefabsInSceneEditorWindow window = GetWindow<MB_ReplacePrefabsInSceneEditorWindow>(true, "Replace Prefabs In Scene", true);
window.Show();
MB_ReplacePrefabsSettings.PrefabPair[] pps = new MB_ReplacePrefabsSettings.PrefabPair[prefabPairs.Length];
for (int i = 0; i < pps.Length; i++)
{
pps[i] = new MB_ReplacePrefabsSettings.PrefabPair()
{
enabled = true,
srcPrefab = prefabPairs[i].sourcePrefab,
targPrefab = prefabPairs[i].resultPrefab,
};
}
window.model.prefabsToSwitch = pps;
window.soModel.Update();
}
private void InitModel()
{
soModel = new SerializedObject(model);
prefabPairs = soModel.FindProperty("prefabsToSwitch");
reverseSrcAndTarg = soModel.FindProperty("reverseSrcAndTarg");
enforceSrcAndTargHaveSameStructure = soModel.FindProperty("enforceSrcAndTargHaveSameStructure");
infoMessages = "";
errorMessages = "";
}
private void OnEnable()
{
minSize = new Vector2(800f, 290f);
if (model == null)
{
model = ScriptableObject.CreateInstance<MB_ReplacePrefabsSettings>();
// Set the Hide flags so that this windows data not destroyed when entering playmode or a new scene.
model.hideFlags = HideFlags.DontSave;
}
InitModel();
}
private void OnGUI()
{
EditorGUILayout.BeginHorizontal();
MB_ReplacePrefabsSettings newModel = (MB_ReplacePrefabsSettings)EditorGUILayout.ObjectField("Settings", model, typeof(MB_ReplacePrefabsSettings), false);
if (newModel != model)
{
if (newModel != null)
{
model = newModel;
}
else
{
if (model == null) model = ScriptableObject.CreateInstance<MB_ReplacePrefabsSettings>();
// Set the Hide flags so that this windows data not destroyed when entering playmode or a new scene.
model.hideFlags = HideFlags.DontSave;
}
InitModel();
}
if (model != null)
{
if (GUILayout.Button("Save Settings", GUILayout.Width(200)))
{
string path = EditorUtility.SaveFilePanel("Save Settings", Application.dataPath, "ReplacePrefabSettings", "asset");
if (path != null)
{
model.hideFlags = HideFlags.None;
string relativepath = "Assets" + path.Substring(Application.dataPath.Length);
Debug.Log("Saved: " + relativepath);
AssetDatabase.CreateAsset(model, relativepath);
}
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.Space();
soModel.Update();
if (GUILayout.Button(GUI_replacePefabsInScene))
{
if (EditorUtility.DisplayDialog("Replace Prefabs In Scene",
"Are you sure you want to replace all source prefab instances with the target prefab instances in this scene? \n\n" +
"It is highly recommended that you back up your scene before doing this.", "OK", "Cancel"))
{
ReplacePrefabsInScene();
}
}
float labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 300f;
EditorGUILayout.PropertyField(reverseSrcAndTarg, GUI_switchSrcAndTarget);
EditorGUILayout.PropertyField(enforceSrcAndTargHaveSameStructure, GUI_enforceSrcAndTargetHaveSameStructure);
EditorGUIUtility.labelWidth = labelWidth;
if (infoMessages != "" || errorMessages != "")
{
EditorGUILayout.HelpBox(errorMessages + "\n" + infoMessages, errorMessages == "" ? MessageType.Info : MessageType.Error);
}
scrollViewPos = EditorGUILayout.BeginScrollView(scrollViewPos);
EditorGUILayout.PropertyField(prefabPairs, true);
EditorGUILayout.EndScrollView();
soModel.ApplyModifiedProperties();
}
private void ReplacePrefabsInScene()
{
MB_ReplacePrefabsInScene rp = new MB_ReplacePrefabsInScene();
rp.replaceEnforceStructure = model.enforceSrcAndTargHaveSameStructure;
int numReplaced = 0;
int numErrors = 0;
errorMessages = "";
infoMessages = "";
EditorUtility.DisplayProgressBar("Replace Prefabs In Scene", "Replace Prefabs In Scene", 0);
for (int i = 0; i < model.prefabsToSwitch.Length; i++)
{
MB_ReplacePrefabsSettings.PrefabPair pp = model.prefabsToSwitch[i];
pp.objsWithErrors.Clear();
if (pp.enabled)
{
GameObject src, targ;
if (model.reverseSrcAndTarg)
{
src = pp.targPrefab;
targ = pp.srcPrefab;
}
else
{
src = pp.srcPrefab;
targ = pp.targPrefab;
}
numReplaced += rp.ReplacePrefabInstancesInScene(src, targ, pp.objsWithErrors);
numErrors += pp.objsWithErrors.Count;
}
EditorUtility.DisplayProgressBar("Replace Prefabs In Scene", "Replace In Scene: " + pp.srcPrefab, (float)i / (float)model.prefabsToSwitch.Length);
}
EditorUtility.ClearProgressBar();
Debug.Log("Total prefab instances replaced: " + numReplaced);
infoMessages = "Total prefab instances replaced: " + numReplaced;
if (numErrors > 0)
{
errorMessages = "There were errors replacing some of the prefabs in the scene. See console for details.";
}
soModel.Update();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 568dea53a514f9a4fa3a4483bad6a0b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_ReplacePrefabsInSceneEditorWindow.cs
uploadId: 797180
@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
[System.Serializable]
public class MB_ReplacePrefabsSettings : ScriptableObject
{
[System.Serializable]
public class PrefabPair
{
public bool enabled = true;
public GameObject srcPrefab;
public GameObject targPrefab;
public List<MB_ReplacePrefabsInScene.Error> objsWithErrors = new List<MB_ReplacePrefabsInScene.Error>();
}
public PrefabPair[] prefabsToSwitch = new PrefabPair[0];
public bool reverseSrcAndTarg;
public bool enforceSrcAndTargHaveSameStructure = true;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f2e44f04becd89f469c0431787b827bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_ReplacePrefabsSettings.cs
uploadId: 797180
@@ -0,0 +1,567 @@
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
using UnityEngine;
using System.IO;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
using UnityEditor;
namespace DigitalOpus.MB.MBEditor
{
public class MB_TextureBakerEditorConfigureMultiMaterials
{
private static GUIContent gc_moveOneMappingUp = new GUIContent("\u2191", "move this material up to previous mapping."),
gc_moveOneMappingDown = new GUIContent("\u2193", "move this material down to next mapping."),
gc_newCombinedMaterial = new GUIContent("new", "Create a new combined material for this mapping.");
private static GUIContent[] gc_SourceMatOptions = new GUIContent[]
{
new GUIContent("...", " Source material actions. "),
new GUIContent("move up to previous submesh", "move this material up to previous submesh."),
new GUIContent("move down to next submesh", "move this material down to next submesh."),
};
private static GUIContent[] gc_MappingOptions = new GUIContent[]
{
new GUIContent("...", " Result material actions. "),
new GUIContent("move submesh up", "Move this submesh up."),
new GUIContent("move submesh down", "Move this submesh down."),
new GUIContent("delete submesh", "Delete this submesh."),
new GUIContent("insert new submesh", "Insert a new submesh after this submesh."),
new GUIContent("create combined material", "Create a combined material for this submesh."),
};
private static GUIContent sourceMaterialsLabel = new GUIContent(
"Source Materials",
"This list of source materials will be combined into a combined-material for this submesh."
);
public static void DrawMapping(MB3_TextureBaker momm, MB3_TextureBakerEditorInternal tbEditor, int rowNum)
{
EditorGUILayout.Separator();
if (rowNum % 2 == 1)
{
EditorGUILayout.BeginVertical(tbEditor.editorStyles.multipleMaterialBackgroundStyle);
}
else
{
EditorGUILayout.BeginVertical(tbEditor.editorStyles.multipleMaterialBackgroundStyleDarker);
}
string s = "";
if (rowNum < momm.resultMaterials.Length && momm.resultMaterials[rowNum] != null && momm.resultMaterials[rowNum].combinedMaterial != null) s = momm.resultMaterials[rowNum].combinedMaterial.shader.ToString();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("---------- submesh:" + rowNum + " " + s, EditorStyles.boldLabel);
int myAction = 0;
myAction = EditorGUILayout.Popup(myAction, gc_MappingOptions, GUILayout.MaxWidth(60f));
if (myAction != 0)
{
if (myAction == 1) // Move submesh up
{
if (rowNum > 0)
{
tbEditor.resultMaterials.MoveArrayElement(rowNum, rowNum - 1);
}
}
if (myAction == 2) // Move submesh down
{
if (rowNum < tbEditor.resultMaterials.arraySize - 1)
{
tbEditor.resultMaterials.MoveArrayElement(rowNum, rowNum + 1);
}
}
if (myAction == 3) // Delete submesh
{
tbEditor.resultMaterials.DeleteArrayElementAtIndex(rowNum);
}
if (myAction == 4) // Insert new submesh
{
tbEditor.resultMaterials.InsertArrayElementAtIndex(rowNum);
}
if (myAction == 5) // Create combined material
{
_CreateCombinedMaterialForSubmesh(momm, tbEditor, rowNum);
}
}
EditorGUILayout.EndHorizontal();
if (rowNum < tbEditor.resultMaterials.arraySize)
{
EditorGUILayout.Separator();
SerializedProperty resMat = tbEditor.resultMaterials.GetArrayElementAtIndex(rowNum);
SerializedProperty combinedMatProp = resMat.FindPropertyRelative("combinedMaterial");
EditorGUILayout.PropertyField(combinedMatProp);
EditorGUILayout.PropertyField(resMat.FindPropertyRelative("considerMeshUVs"));
DrawMappingSourceMaterials(resMat, tbEditor, rowNum);
}
EditorGUILayout.EndVertical();
}
static void _CreateCombinedMaterialForSubmesh(MB3_TextureBaker momm, MB3_TextureBakerEditorInternal tbEditor, int rowNum)
{
string newMatPath = EditorUtility.SaveFilePanelInProject("Asset name", "", "mat", "Enter a name for the baked material");
if (newMatPath != null && newMatPath.Length > 4)
{
Material newMat = null;
{
if (momm.resultMaterials[rowNum].sourceMaterials.Count > 0)
{
Material sourceMat = momm.resultMaterials[rowNum].sourceMaterials[0];
if (sourceMat != null)
{
newMat = new Material(sourceMat);
MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, sourceMat);
}
}
}
if (newMat == null)
{
newMat = new Material(Shader.Find("Diffuse"));
}
AssetDatabase.CreateAsset(newMat, newMatPath);
var assetRef = (Material)AssetDatabase.LoadAssetAtPath(newMatPath, typeof(Material));
SerializedProperty resMat = tbEditor.resultMaterials.GetArrayElementAtIndex(rowNum);
SerializedProperty combinedMatProp = resMat.FindPropertyRelative("combinedMaterial");
combinedMatProp.objectReferenceValue = assetRef;
}
}
public static void DrawMappingSourceMaterials(SerializedProperty resMat, MB3_TextureBakerEditorInternal tbEditor, int rowNum)
{
EditorGUILayout.LabelField(sourceMaterialsLabel);
SerializedProperty sourceMats = resMat.FindPropertyRelative("sourceMaterials");
bool showListSize = true;
EditorGUI.indentLevel += 1;
sourceMats.isExpanded = true;
if (sourceMats.isExpanded)
{
if (showListSize)
{
EditorGUILayout.PropertyField(sourceMats.FindPropertyRelative("Array.size"));
}
for (int i = 0; i < sourceMats.arraySize; i++)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(sourceMats.GetArrayElementAtIndex(i));
// ========================
{
int myAction = 0;
myAction = EditorGUILayout.Popup(myAction, gc_SourceMatOptions, GUILayout.MaxWidth(60f));
if (myAction != 0)
{
if (myAction == 1) // move source mat up one mapping
{
if (rowNum > 0)
{
SerializedProperty resMatUp = tbEditor.resultMaterials.GetArrayElementAtIndex(rowNum - 1);
SerializedProperty sourceMatsUp = resMatUp.FindPropertyRelative("sourceMaterials");
int idx = sourceMatsUp.arraySize;
sourceMatsUp.InsertArrayElementAtIndex(idx);
sourceMatsUp.GetArrayElementAtIndex(idx).objectReferenceValue = sourceMats.GetArrayElementAtIndex(i).objectReferenceValue;
sourceMats.DeleteArrayElementAtIndex(i);
}
}
if (myAction == 2) // move source mat down one mapping
{
if (rowNum < tbEditor.resultMaterials.arraySize - 1)
{
SerializedProperty resMatDown = tbEditor.resultMaterials.GetArrayElementAtIndex(rowNum + 1);
SerializedProperty sourceMatsDown = resMatDown.FindPropertyRelative("sourceMaterials");
sourceMatsDown.InsertArrayElementAtIndex(0);
sourceMatsDown.GetArrayElementAtIndex(0).objectReferenceValue = sourceMats.GetArrayElementAtIndex(i).objectReferenceValue;
sourceMats.DeleteArrayElementAtIndex(i);
}
}
}
}
EditorGUILayout.EndHorizontal();
}
}
EditorGUI.indentLevel -= 1;
}
public static void DrawMultipleMaterialsMappings(MB3_TextureBaker momm, SerializedObject textureBaker, MB3_TextureBakerEditorInternal tbEditor)
{
EditorGUILayout.BeginVertical(tbEditor.editorStyles.multipleMaterialBackgroundStyle);
EditorGUILayout.LabelField("Source Material To Combined Mapping", EditorStyles.boldLabel);
float oldLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 300;
EditorGUILayout.PropertyField(tbEditor.doMultiMaterialIfOBUVs, MB3_TextureBakerEditorInternal.gc_DoMultiMaterialSplitAtlasesIfOBUVs);
EditorGUILayout.PropertyField(tbEditor.doMultiMaterialSplitAtlasesIfTooBig, MB3_TextureBakerEditorInternal.gc_DoMultiMaterialSplitAtlasesIfTooBig);
EditorGUIUtility.labelWidth = oldLabelWidth;
if (GUILayout.Button(MB3_TextureBakerEditorInternal.configAtlasMultiMatsFromObjsContent))
{
MB_TextureBakerEditorConfigureMultiMaterials.ConfigureMutiMaterialsFromObjsToCombine(momm, tbEditor.resultMaterials, textureBaker);
}
EditorGUILayout.BeginHorizontal();
tbEditor.resultMaterialsFoldout = EditorGUILayout.Foldout(tbEditor.resultMaterialsFoldout, MB3_TextureBakerEditorInternal.combinedMaterialsGUIContent);
if (GUILayout.Button(MB3_TextureBakerEditorInternal.insertContent, EditorStyles.miniButtonLeft, MB3_TextureBakerEditorInternal.buttonWidth))
{
if (tbEditor.resultMaterials.arraySize == 0)
{
momm.resultMaterials = new MB_MultiMaterial[1];
momm.resultMaterials[0] = new MB_MultiMaterial();
momm.resultMaterials[0].considerMeshUVs = momm.fixOutOfBoundsUVs;
}
else
{
int idx = tbEditor.resultMaterials.arraySize - 1;
tbEditor.resultMaterials.InsertArrayElementAtIndex(idx);
tbEditor.resultMaterials.GetArrayElementAtIndex(idx + 1).FindPropertyRelative("considerMeshUVs").boolValue = momm.fixOutOfBoundsUVs;
}
}
if (GUILayout.Button(MB3_TextureBakerEditorInternal.deleteContent, EditorStyles.miniButtonRight, MB3_TextureBakerEditorInternal.buttonWidth)
&& tbEditor.resultMaterials.arraySize > 0)
{
tbEditor.resultMaterials.DeleteArrayElementAtIndex(tbEditor.resultMaterials.arraySize - 1);
}
EditorGUILayout.EndHorizontal();
if (tbEditor.resultMaterialsFoldout)
{
for (int i = 0; i < tbEditor.resultMaterials.arraySize; i++)
{
DrawMapping(momm, tbEditor, i);
}
}
EditorGUILayout.EndVertical();
}
/* tried to see if the MultiMaterialConfig could be done using the GroupBy filters. Saddly it didn't work */
public static void ConfigureMutiMaterialsFromObjsToCombine2(MB3_TextureBaker mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
{
if (mom.GetObjectsToCombine().Count == 0)
{
Debug.LogError("You need to add some objects to combine before building the multi material list.");
return;
}
if (resultMaterials.arraySize > 0)
{
Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation.");
return;
}
if (mom.textureBakeResults == null)
{
Debug.LogError("Texture Bake Result asset must be set before using this operation.");
return;
}
//validate that the objects to be combined are valid
for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
{
GameObject go = mom.GetObjectsToCombine()[i];
if (go == null)
{
Debug.LogError("Null object in list of objects to combine at position " + i);
return;
}
Renderer r = go.GetComponent<Renderer>();
if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
{
Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
return;
}
if (r.sharedMaterial == null)
{
Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
return;
}
}
IGroupByFilter[] filters = new IGroupByFilter[3];
filters[0] = new GroupByOutOfBoundsUVs();
filters[1] = new GroupByShader();
filters[2] = new MB3_GroupByTransparency();
List<GameObjectFilterInfo> gameObjects = new List<GameObjectFilterInfo>();
HashSet<GameObject> objectsAlreadyIncludedInBakers = new HashSet<GameObject>();
for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
{
GameObjectFilterInfo goaw = new GameObjectFilterInfo(mom.GetObjectsToCombine()[i], objectsAlreadyIncludedInBakers, filters);
if (goaw.materials.Length > 0) //don't consider renderers with no materials
{
gameObjects.Add(goaw);
}
}
//analyse meshes
Dictionary<int, MB_Utility.MeshAnalysisResult> meshAnalysisResultCache = new Dictionary<int, MB_Utility.MeshAnalysisResult>();
int totalVerts = 0;
for (int i = 0; i < gameObjects.Count; i++)
{
//string rpt = String.Format("Processing {0} [{1} of {2}]", gameObjects[i].go.name, i, gameObjects.Count);
//EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " A", .6f);
Mesh mm = MB_Utility.GetMesh(gameObjects[i].go);
int nVerts = 0;
if (mm != null)
{
nVerts += mm.vertexCount;
MB_Utility.MeshAnalysisResult mar;
if (!meshAnalysisResultCache.TryGetValue(mm.GetInstanceID(), out mar))
{
//EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Check Out Of Bounds UVs", .6f);
MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
//Rect dummy = mar.uvRect;
MB_Utility.doSubmeshesShareVertsOrTris(mm, ref mar);
meshAnalysisResultCache.Add(mm.GetInstanceID(), mar);
}
if (mar.hasOutOfBoundsUVs)
{
int w = (int)mar.uvRect.width;
int h = (int)mar.uvRect.height;
gameObjects[i].outOfBoundsUVs = true;
gameObjects[i].warning.AppendLine(" [WARNING: has uvs outside the range (0,1) tex is tiled " + w + "x" + h + " times]");
}
if (mar.hasOverlappingSubmeshVerts)
{
gameObjects[i].submeshesOverlap = true;
gameObjects[i].warning.AppendLine(" [WARNING: Submeshes share verts or triangles. 'Multiple Combined Materials' feature may not work.]");
}
}
totalVerts += nVerts;
//EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Validate OBuvs Multi Material", .6f);
Renderer mr = gameObjects[i].go.GetComponent<Renderer>();
if (!MB_Utility.AreAllSharedMaterialsDistinct(mr.sharedMaterials))
{
gameObjects[i].warning.AppendLine(" [WARNING: Object uses same material on multiple submeshes. This may produce poor results when used with multiple materials or Consider Mesh UVs.]");
}
}
List<GameObjectFilterInfo> objsNotAddedToBaker = new List<GameObjectFilterInfo>();
Dictionary<GameObjectFilterInfo, List<List<GameObjectFilterInfo>>> gs2bakeGroupMap = MB3_MeshBakerEditorWindowAnalyseSceneTab.sortIntoBakeGroups3(gameObjects, objsNotAddedToBaker, filters, false, mom.maxAtlasSize);
mom.resultMaterials = new MB_MultiMaterial[gs2bakeGroupMap.Keys.Count];
string pth = AssetDatabase.GetAssetPath(mom.textureBakeResults);
string baseName = Path.GetFileNameWithoutExtension(pth);
string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
int k = 0;
foreach (GameObjectFilterInfo m in gs2bakeGroupMap.Keys)
{
MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
mm.sourceMaterials = new List<Material>();
mm.sourceMaterials.Add(m.materials[0]);
string matName = folderPath + baseName + "-mat" + k + ".mat";
Material newMat = new Material(Shader.Find("Diffuse"));
MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, m.materials[0]);
AssetDatabase.CreateAsset(newMat, matName);
mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
k++;
}
MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
}
//posibilities
// using fixOutOfBoundsUVs or not
//
public static void ConfigureMutiMaterialsFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
{
if (mom.GetObjectsToCombine().Count == 0)
{
Debug.LogError("You need to add some objects to combine before building the multi material list.");
return;
}
if (resultMaterials.arraySize > 0)
{
Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation.");
return;
}
if (mom.textureBakeResults == null)
{
Debug.LogError("Texture Bake Result asset must be set before using this operation.");
return;
}
Dictionary<MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List<List<Material>>> shader2Material_map = new Dictionary<MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List<List<Material>>>();
Dictionary<Material, Mesh> obUVobject2mesh_map = new Dictionary<Material, Mesh>();
//validate that the objects to be combined are valid
for (int goIdx = 0; goIdx < mom.GetObjectsToCombine().Count; goIdx++)
{
GameObject go = mom.GetObjectsToCombine()[goIdx];
if (go == null)
{
Debug.LogError("Null object in list of objects to combine at position " + goIdx);
return;
}
Renderer r = go.GetComponent<Renderer>();
if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
{
Debug.LogError("GameObject at position " + goIdx + " in list of objects to combine did not have a renderer");
return;
}
for (int matIdx = 0; matIdx < r.sharedMaterials.Length; matIdx++)
{
if (r.sharedMaterials[matIdx] == null)
{
Debug.LogError("GameObject " + go + " at position " + goIdx + " in list of objects to combine has one or more null materials");
return;
}
}
}
//first pass put any meshes with obUVs on their own submesh if not fixing OB uvs
if (mom.doMultiMaterialSplitAtlasesIfOBUVs)
{
for (int goIdx = 0; goIdx < mom.GetObjectsToCombine().Count; goIdx++)
{
GameObject go = mom.GetObjectsToCombine()[goIdx];
Mesh m = MB_Utility.GetMesh(go);
MB_Utility.MeshAnalysisResult dummyMar = new MB_Utility.MeshAnalysisResult();
Renderer r = go.GetComponent<Renderer>();
for (int matIdx = 0; matIdx < r.sharedMaterials.Length; matIdx++)
{
if (MB_Utility.hasOutOfBoundsUVs(m, ref dummyMar, matIdx))
{
if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[matIdx]))
{
Debug.LogWarning("Object " + go + " submesh " + matIdx + " uses UVs outside the range 0,0..1,1 to generate tiling. This object has been mapped to its own submesh in the combined mesh. It can share a submesh with other objects that use different materials if you use the Consider Mesh UVs feature which will bake the tiling");
obUVobject2mesh_map.Add(r.sharedMaterials[matIdx], m);
}
}
}
}
}
//second pass put other materials without OB uvs in a shader to material map
for (int goIdx = 0; goIdx < mom.GetObjectsToCombine().Count; goIdx++)
{
Renderer r = mom.GetObjectsToCombine()[goIdx].GetComponent<Renderer>();
for (int matIdx = 0; matIdx < r.sharedMaterials.Length; matIdx++)
{
if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[matIdx]))
{ //if not already added
if (r.sharedMaterials[matIdx] == null) continue;
List<List<Material>> binsOfMatsThatUseShader = null;
MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo newKey = new MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo(r.sharedMaterials[matIdx].shader, r.sharedMaterials[matIdx]);
if (!shader2Material_map.TryGetValue(newKey, out binsOfMatsThatUseShader))
{
binsOfMatsThatUseShader = new List<List<Material>>();
binsOfMatsThatUseShader.Add(new List<Material>());
shader2Material_map.Add(newKey, binsOfMatsThatUseShader);
}
if (!binsOfMatsThatUseShader[0].Contains(r.sharedMaterials[matIdx])) binsOfMatsThatUseShader[0].Add(r.sharedMaterials[matIdx]);
}
}
}
int numResMats = shader2Material_map.Count;
//third pass for each shader grouping check how big the atlas would be and group into bins that would fit in an atlas
if (mom.doMultiMaterialSplitAtlasesIfTooBig)
{
if (mom.packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures)
{
Debug.LogWarning("Unity texture packer does not support splitting atlases if too big. Atlases will not be split.");
}
else
{
numResMats = 0;
foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo sh in shader2Material_map.Keys)
{
List<List<Material>> binsOfMatsThatUseShader = shader2Material_map[sh];
List<Material> allMatsThatUserShader = binsOfMatsThatUseShader[0];//at this point everything is in the same list
binsOfMatsThatUseShader.RemoveAt(0);
MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
combiner.saveAtlasesAsAssets = false;
if (allMatsThatUserShader.Count > 1) combiner.fixOutOfBoundsUVs = mom.fixOutOfBoundsUVs;
else combiner.fixOutOfBoundsUVs = false;
// Do the texture pack
List<AtlasPackingResult> packingResults = new List<AtlasPackingResult>();
Material tempMat = new Material(sh.shader);
MB_AtlasesAndRects atlasesAndRects = new MB_AtlasesAndRects();
combiner.CombineTexturesIntoAtlases(null, atlasesAndRects, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, mom.texturePropNamesToIgnore, null, packingResults,
onlyPackRects: true, splitAtlasWhenPackingIfTooBig: true);
for (int aprIdx = 0; aprIdx < packingResults.Count; aprIdx++)
{
List<MB_MaterialAndUVRect> matsData = (List<MB_MaterialAndUVRect>)packingResults[aprIdx].data;
List<Material> mats = new List<Material>();
for (int mdIdx = 0; mdIdx < matsData.Count; mdIdx++)
{
Material mat = matsData[mdIdx].material;
if (!mats.Contains(mat))
{
mats.Add(mat);
}
}
binsOfMatsThatUseShader.Add(mats);
}
numResMats += binsOfMatsThatUseShader.Count;
}
}
}
//build the result materials
if (shader2Material_map.Count == 0 && obUVobject2mesh_map.Count == 0) Debug.LogError("Found no materials in list of objects to combine");
mom.resultMaterials = new MB_MultiMaterial[numResMats + obUVobject2mesh_map.Count];
string pth = AssetDatabase.GetAssetPath(mom.textureBakeResults);
string baseName = Path.GetFileNameWithoutExtension(pth);
string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
int k = 0;
foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo sh in shader2Material_map.Keys)
{
foreach (List<Material> matsThatUse in shader2Material_map[sh])
{
MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
mm.sourceMaterials = matsThatUse;
if (mm.sourceMaterials.Count == 1)
{
mm.considerMeshUVs = false;
}
else
{
mm.considerMeshUVs = mom.fixOutOfBoundsUVs;
}
string matName = folderPath + baseName + "-mat" + k + ".mat";
Material newMat = new Material(Shader.Find("Diffuse"));
if (matsThatUse.Count > 0 && matsThatUse[0] != null)
{
MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, matsThatUse[0]);
}
AssetDatabase.CreateAsset(newMat, matName);
mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
k++;
}
}
foreach (Material m in obUVobject2mesh_map.Keys)
{
MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
mm.sourceMaterials = new List<Material>();
mm.sourceMaterials.Add(m);
mm.considerMeshUVs = false;
string matName = folderPath + baseName + "-mat" + k + ".mat";
Material newMat = new Material(Shader.Find("Diffuse"));
MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, m);
AssetDatabase.CreateAsset(newMat, matName);
mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
k++;
}
MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a61c02ab9beccee4aa8d443c9e2625fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_TextureBakerEditorConfigureMultiMaterials.cs
uploadId: 797180
@@ -0,0 +1,550 @@
//----------------------------------------------
// MeshBaker
// Copyright © 2011-2012 Ian Deane
//----------------------------------------------
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;
namespace DigitalOpus.MB.MBEditor
{
public class MB_TextureBakerConfigureTextureArrays
{
private class Slice
{
public List<MB_MaterialAndUVRect> atlasRects;
public AtlasPackingResult packingResult;
public int numAtlasRects;
}
private static GUIContent gc_TextureArrayOutputFormats = new GUIContent(
"Texture Array Output Formats",
"Texture Arrays do not have a 'TextureImporter' that lets you change the TextureArray format." +
"You can provide a list of formats to be generated here. You will probably have one set of formats per platform.");
public static void DrawTextureArrayConfiguration(MB3_TextureBaker momm, SerializedObject textureBaker, MB3_TextureBakerEditorInternal editorInternal)
{
EditorGUILayout.BeginVertical(editorInternal.editorStyles.multipleMaterialBackgroundStyle);
EditorGUILayout.LabelField("Texture Array Slice Configuration", EditorStyles.boldLabel);
float oldLabelWidth = EditorGUIUtility.labelWidth;
if (GUILayout.Button(MB3_TextureBakerEditorInternal.configAtlasTextureSlicesFromObjsContent))
{
ConfigureTextureArraysFromObjsToCombine(momm, editorInternal.resultMaterialsTexArray, textureBaker);
}
if (GUILayout.Button("Report texture sizes"))
{
Debug.Log(ReportTextureSizesAndFormats(momm));
}
if (editorInternal.textureArrayOutputFormats.arraySize == 0)
{
EditorGUILayout.HelpBox("You need at least one output format.", MessageType.Error);
}
EditorGUILayout.PropertyField(editorInternal.textureArrayOutputFormats, gc_TextureArrayOutputFormats, true);
EditorGUILayout.BeginHorizontal();
editorInternal.resultMaterialsFoldout = EditorGUILayout.Foldout(editorInternal.resultMaterialsFoldout, MB3_TextureBakerEditorInternal.textureArrayCombinedMaterialFoldoutGUIContent);
if (GUILayout.Button(MB3_TextureBakerEditorInternal.insertContent, EditorStyles.miniButtonLeft, MB3_TextureBakerEditorInternal.buttonWidth))
{
if (editorInternal.resultMaterialsTexArray.arraySize == 0)
{
momm.resultMaterialsTexArray = new MB_MultiMaterialTexArray[1];
}
else
{
int idx = editorInternal.resultMaterialsTexArray.arraySize - 1;
editorInternal.resultMaterialsTexArray.InsertArrayElementAtIndex(idx);
}
}
if (GUILayout.Button(MB3_TextureBakerEditorInternal.deleteContent, EditorStyles.miniButtonRight, MB3_TextureBakerEditorInternal.buttonWidth)
&& editorInternal.resultMaterialsTexArray.arraySize > 0)
{
editorInternal.resultMaterialsTexArray.DeleteArrayElementAtIndex(editorInternal.resultMaterialsTexArray.arraySize - 1);
}
EditorGUILayout.EndHorizontal();
if (editorInternal.resultMaterialsFoldout)
{
for (int i = 0; i < editorInternal.resultMaterialsTexArray.arraySize; i++)
{
EditorGUILayout.Separator();
if (i % 2 == 1)
{
EditorGUILayout.BeginVertical(editorInternal.editorStyles.multipleMaterialBackgroundStyle);
}
else
{
EditorGUILayout.BeginVertical(editorInternal.editorStyles.multipleMaterialBackgroundStyleDarker);
}
string s = "";
if (i < momm.resultMaterialsTexArray.Length && momm.resultMaterialsTexArray[i] != null && momm.resultMaterialsTexArray[i].combinedMaterial != null) s = momm.resultMaterialsTexArray[i].combinedMaterial.shader.ToString();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("---------- submesh:" + i + " " + s, EditorStyles.boldLabel);
if (GUILayout.Button(MB3_TextureBakerEditorInternal.deleteContent, EditorStyles.miniButtonRight, MB3_TextureBakerEditorInternal.buttonWidth))
{
editorInternal.resultMaterialsTexArray.DeleteArrayElementAtIndex(i);
}
EditorGUILayout.EndHorizontal();
if (i < editorInternal.resultMaterialsTexArray.arraySize)
{
EditorGUILayout.Separator();
SerializedProperty resMat = editorInternal.resultMaterialsTexArray.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(resMat.FindPropertyRelative("combinedMaterial"));
SerializedProperty slices = resMat.FindPropertyRelative("slices");
EditorGUILayout.PropertyField(slices, true);
}
EditorGUILayout.EndVertical();
}
}
EditorGUILayout.EndVertical();
}
public static string ReportTextureSizesAndFormats(MB3_TextureBaker mom)
{
if (mom.resultType != MB2_TextureBakeResults.ResultType.textureArray)
{
Debug.LogError("Result Type must be Texture Array.");
return "";
}
for (int resMatIdx = 0; resMatIdx < mom.resultMaterialsTexArray.Length; resMatIdx++)
{
MB_MultiMaterialTexArray resMatTexArray = mom.resultMaterialsTexArray[resMatIdx];
if (resMatTexArray.combinedMaterial == null)
{
Debug.LogError("Result Material " + resMatIdx + " is null");
return "";
}
}
System.Text.StringBuilder sb = new System.Text.StringBuilder();
// Visit each result material
for (int resMatIdx = 0; resMatIdx < mom.resultMaterialsTexArray.Length; resMatIdx++)
{
MB_MultiMaterialTexArray resMatTexArray = mom.resultMaterialsTexArray[resMatIdx];
// Do an atlas pack in order to collect all the textures needed by the result material
// And group these by material texture property.
MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
combiner.saveAtlasesAsAssets = false;
combiner.fixOutOfBoundsUVs = false;
List<AtlasPackingResult> packingResults = new List<AtlasPackingResult>();
Material tempMat = new Material(resMatTexArray.combinedMaterial.shader);
List<Material> allSourceMaterials = new List<Material>();
for (int sliceIdx = 0; sliceIdx < resMatTexArray.slices.Count; sliceIdx++)
{
List<Material> srcMats = new List<Material>();
resMatTexArray.slices[sliceIdx].GetAllUsedMaterials(srcMats);
for (int srcMatIdx = 0; srcMatIdx < srcMats.Count; srcMatIdx++)
{
if (srcMats[srcMatIdx] != null && !allSourceMaterials.Contains(srcMats[srcMatIdx]))
{
allSourceMaterials.Add(srcMats[srcMatIdx]);
}
}
}
MB_AtlasesAndRects atlasesAndRects = new MB_AtlasesAndRects();
combiner.CombineTexturesIntoAtlases(null, atlasesAndRects, tempMat, mom.GetObjectsToCombine(), allSourceMaterials, mom.texturePropNamesToIgnore, null, packingResults,
onlyPackRects:true, splitAtlasWhenPackingIfTooBig:false);
// Now vist the packing results and collect all the textures
Debug.Assert(packingResults.Count == 1);
for (int texPropIdx = 0; texPropIdx < atlasesAndRects.texPropertyNames.Length; texPropIdx++)
{
string propertyName = atlasesAndRects.texPropertyNames[texPropIdx];
sb.AppendLine(String.Format("Prop: {0}", propertyName));
List<MB_MaterialAndUVRect> matsData = (List<MB_MaterialAndUVRect>)packingResults[0].data;
HashSet<Material> visitedMats = new HashSet<Material>();
for (int matAndGoIdx = 0; matAndGoIdx < matsData.Count; matAndGoIdx++)
{
Material mat = matsData[matAndGoIdx].material;
if (visitedMats.Contains(mat)) continue;
visitedMats.Add(mat);
if (mat.HasProperty(propertyName))
{
Texture tex = mat.GetTexture(propertyName);
if (tex != null)
{
string texFormatString = "UnknownFormat";
string texWrapMode = "UnknownClampMode";
if (tex is Texture2D)
{
texFormatString = ((Texture2D)tex).format.ToString();
texWrapMode = ((Texture2D)tex).wrapMode.ToString();
}
sb.AppendLine(String.Format(" {0} x {1} format:{2} wrapMode:{3} {4}", tex.width.ToString().PadLeft(6,' '), tex.height.ToString().PadRight(6,' '), texFormatString.PadRight(20,' '), texWrapMode.PadRight(12,' '), tex.name));
}
}
}
}
}
return sb.ToString();
}
public static void ConfigureTextureArraysFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterialsTexArrays, SerializedObject textureBaker)
{
if (mom.GetObjectsToCombine().Count == 0)
{
Debug.LogError("You need to add some objects to combine before building the texture array result materials.");
return;
}
if (resultMaterialsTexArrays.arraySize > 0)
{
Debug.LogError("You already have some texture array result materials configured. You must remove these before doing this operation.");
return;
}
if (mom.textureBakeResults == null)
{
Debug.LogError("Texture Bake Result asset must be set before using this operation.");
return;
}
//validate that the objects to be combined are valid
for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
{
GameObject go = mom.GetObjectsToCombine()[i];
if (go == null)
{
Debug.LogError("Null object in list of objects to combine at position " + i);
return;
}
if (MB_Utility.GetMesh(go) == null)
{
Debug.LogError("Could not get mesh for object in list of objects to combine at position " + i);
return;
}
Renderer r = go.GetComponent<Renderer>();
if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
{
Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
return;
}
if (r.sharedMaterial == null)
{
Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
return;
}
}
//Will sort into "result material"
// slices
Dictionary<MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List<Slice>> shader2ResultMat_map = new Dictionary<MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List<Slice>>();
// first pass split by shader and analyse meshes.
List<GameObject> objsToCombine = mom.GetObjectsToCombine();
for (int meshIdx = 0; meshIdx < objsToCombine.Count; meshIdx++)
{
GameObject srcGo = objsToCombine[meshIdx];
Mesh mesh = MB_Utility.GetMesh(srcGo);
Renderer r = MB_Utility.GetRenderer(srcGo);
if (mom.LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log("1st Pass 'Split By Shader' Processing Mesh: "+ mesh +" Num submeshes: " + r.sharedMaterials.Length);
for (int submeshIdx = 0; submeshIdx < r.sharedMaterials.Length; submeshIdx++)
{
if (r.sharedMaterials[submeshIdx] == null) continue;
MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo newKey = new MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo(r.sharedMaterials[submeshIdx].shader, r.sharedMaterials[submeshIdx]);
// Initially we fill the list of srcMaterials with garbage MB_MaterialAndUVRects. Will get proper ones when we atlas pack.
MB_MaterialAndUVRect submeshMaterial = new MB_MaterialAndUVRect(
r.sharedMaterials[submeshIdx],
new Rect(0, 0, 0, 0), // garbage value
false, //garbage value
new Rect(0, 0, 0, 0), // garbage value
new Rect(0, 0, 0, 0), // garbage value
new Rect(0, 0, 1, 1), // garbage value
MB_TextureTilingTreatment.unknown, // garbage value
r.name);
submeshMaterial.objectsThatUse = new List<GameObject>();
submeshMaterial.objectsThatUse.Add(r.gameObject);
if (!shader2ResultMat_map.ContainsKey(newKey))
{
// this is a new shader create a new result material
Slice srcMaterials = new Slice
{
atlasRects = new List<MB_MaterialAndUVRect>(),
numAtlasRects = 1,
};
srcMaterials.atlasRects.Add(submeshMaterial);
List<Slice> binsOfMatsThatUseShader = new List<Slice>();
binsOfMatsThatUseShader.Add(srcMaterials);
if (mom.LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(" Adding Source Material: " + submeshMaterial.material);
shader2ResultMat_map.Add(newKey, binsOfMatsThatUseShader);
}
else
{
// there is a result material that uses this shader. Add this source material
Slice srcMaterials = shader2ResultMat_map[newKey][0]; // There should only be one list of source materials
if (srcMaterials.atlasRects.Find(x => x.material == submeshMaterial.material) == null)
{
if (mom.LOG_LEVEL >= MB2_LogLevel.trace) Debug.Log(" Adding Source Material: " + submeshMaterial.material);
srcMaterials.atlasRects.Add(submeshMaterial);
}
}
}
}
int resMatCount = 0;
foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resultMat in shader2ResultMat_map.Keys)
{
// at this point there there should be only one slice with all the source materials
resMatCount++;
// For each result material, all source materials are in the first slice.
// We will now split these using a texture packer. Each "atlas" generated by the packer will be a slice.
{
// All source materials should be in the first slice at this point.
List<Slice> slices = shader2ResultMat_map[resultMat];
List<Slice> newSlices = new List<Slice>();
Slice firstSlice = slices[0];
List<Material> allMatsThatUserShader = new List<Material>();
List<GameObject> objsThatUseFirstSlice = new List<GameObject>();
for (int i = 0; i < firstSlice.atlasRects.Count; i++)
{
allMatsThatUserShader.Add(firstSlice.atlasRects[i].material);
if (!objsThatUseFirstSlice.Contains(firstSlice.atlasRects[i].objectsThatUse[0]))
{
objsThatUseFirstSlice.Add(firstSlice.atlasRects[i].objectsThatUse[0]);
}
}
MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
combiner.packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
combiner.saveAtlasesAsAssets = false;
combiner.fixOutOfBoundsUVs = true;
combiner.doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize = true;
List<AtlasPackingResult> packingResults = new List<AtlasPackingResult>();
Material tempMat = new Material(resultMat.shader);
if (mom.LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("======== 2nd pass. Use atlas packer to split the first slice into multiple if it exceeds atlas size. ");
combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, mom.texturePropNamesToIgnore, null, packingResults,
onlyPackRects:true, splitAtlasWhenPackingIfTooBig:true);
if (mom.LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("======== Completed packing with texture packer. numPackingResults: " + packingResults.Count);
newSlices.Clear();
// The texture packing just split the atlas into multiple atlases. Each atlas will become a "slice".
for (int newSliceIdx = 0; newSliceIdx < packingResults.Count; newSliceIdx++)
{
List<MB_MaterialAndUVRect> sourceMats = new List<MB_MaterialAndUVRect>();
List<MB_MaterialAndUVRect> packedMatRects = (List<MB_MaterialAndUVRect>) packingResults[newSliceIdx].data;
HashSet<Rect> distinctAtlasRects = new HashSet<Rect>();
for (int packedMatRectIdx = 0; packedMatRectIdx < packedMatRects.Count; packedMatRectIdx++)
{
MB_MaterialAndUVRect muvr = packedMatRects[packedMatRectIdx];
distinctAtlasRects.Add(muvr.atlasRect);
//{
// Rect encapsulatingRect = muvr.GetEncapsulatingRect();
// Vector2 sizeInAtlas_px = new Vector2(
// packingResults[newSliceIdx].atlasX * encapsulatingRect.width,
// packingResults[newSliceIdx].atlasY * encapsulatingRect.height);
//}
sourceMats.Add(muvr);
}
Slice slice = new Slice()
{
atlasRects = sourceMats,
packingResult = packingResults[newSliceIdx],
numAtlasRects = distinctAtlasRects.Count,
};
newSlices.Add(slice);
}
// Replace first slice with split version.
if (mom.LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("First slice exceeded atlas size splitting it into " + newSlices.Count + " slices");
slices.RemoveAt(0);
for (int i = 0; i < newSlices.Count; i++)
{
slices.Insert(i, newSlices[i]);
}
}
}
// build the texture array result materials
if (shader2ResultMat_map.Count == 0) Debug.LogError("Found no materials in list of objects to combine");
mom.resultMaterialsTexArray = new MB_MultiMaterialTexArray[shader2ResultMat_map.Count];
int k = 0;
foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resMatKey in shader2ResultMat_map.Keys)
{
List<Slice> srcSlices = shader2ResultMat_map[resMatKey];
MB_MultiMaterialTexArray mm = mom.resultMaterialsTexArray[k] = new MB_MultiMaterialTexArray();
for (int sliceIdx = 0; sliceIdx < srcSlices.Count; sliceIdx++)
{
Slice slice = srcSlices[sliceIdx];
MB_TexArraySlice resSlice = new MB_TexArraySlice();
for (int srcMatIdx = 0; srcMatIdx < slice.atlasRects.Count; srcMatIdx++)
{
MB_MaterialAndUVRect matAndUVRect = slice.atlasRects[srcMatIdx];
List<GameObject> objsThatUse = matAndUVRect.objectsThatUse;
for (int objsThatUseIdx = 0; objsThatUseIdx < objsThatUse.Count; objsThatUseIdx++)
{
GameObject obj = objsThatUse[objsThatUseIdx];
if (!resSlice.ContainsMaterialAndMesh(slice.atlasRects[srcMatIdx].material, MB_Utility.GetMesh(obj)))
{
resSlice.sourceMaterials.Add(
new MB_TexArraySliceRendererMatPair()
{
renderer = obj,
sourceMaterial = slice.atlasRects[srcMatIdx].material
}
);
}
}
}
{
// Should we use considerUVs
bool doConsiderUVs = false;
// If there is more than one atlas rectangle in a slice then use considerUVs
if (slice.numAtlasRects > 1)
{
doConsiderUVs = true;
}
else
{
// There is only one source material, could be:
// - lots of tiling (don't want consider UVs)
// - We are extracting a small part of a large atlas (want considerUVs)
if (slice.packingResult.atlasX >= mom.maxAtlasSize ||
slice.packingResult.atlasY >= mom.maxAtlasSize)
{
doConsiderUVs = false; // lots of tiling
}
else
{
doConsiderUVs = true; // extracting a small part of an atlas
}
}
resSlice.considerMeshUVs = doConsiderUVs;
}
mm.slices.Add(resSlice);
}
// Enforce integrity. If a material appears in more than one slice then all those slices must be considerUVs=true
{
// collect all distinct materials
HashSet<Material> distinctMats = new HashSet<Material>();
Dictionary<Material, int> mat2sliceCount = new Dictionary<Material, int>();
for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
{
for (int sliceMatIdx = 0; sliceMatIdx < mm.slices[sliceIdx].sourceMaterials.Count; sliceMatIdx++)
{
Material mat = mm.slices[sliceIdx].sourceMaterials[sliceMatIdx].sourceMaterial;
distinctMats.Add(mat);
mat2sliceCount[mat] = 0;
}
}
// Count the number of slices that use each material.
foreach (Material mat in distinctMats)
{
for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
{
if (mm.slices[sliceIdx].ContainsMaterial(mat))
{
mat2sliceCount[mat] = mat2sliceCount[mat] + 1;
}
}
}
// Check that considerUVs is true for any materials that appear more than once
foreach (Material mat in distinctMats)
{
if (mat2sliceCount[mat] > 1)
{
for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
{
if (mm.slices[sliceIdx].ContainsMaterial(mat))
{
if (mom.LOG_LEVEL >= MB2_LogLevel.debug &&
mm.slices[sliceIdx].considerMeshUVs) Debug.Log("There was a material " + mat + " that was used by more than one slice and considerUVs was false. sliceIdx:" + sliceIdx);
mm.slices[sliceIdx].considerMeshUVs = true;
}
}
}
}
}
// Cleanup. remove "Renderer"s from source materials that do not use considerUVs and delete extra
{
// put any slices with consider UVs first
List<MB_TexArraySlice> newSlices = new List<MB_TexArraySlice>();
for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
{
if (mm.slices[sliceIdx].considerMeshUVs == true)
{
newSlices.Add(mm.slices[sliceIdx]);
}
}
// for any slices without considerUVs, remove "renderer" and truncate
for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
{
MB_TexArraySlice slice = mm.slices[sliceIdx];
if (slice.considerMeshUVs == false)
{
newSlices.Add(slice);
HashSet<Material> distinctMats = slice.GetDistinctMaterials();
slice.sourceMaterials.Clear();
foreach (Material mat in distinctMats)
{
slice.sourceMaterials.Add(new MB_TexArraySliceRendererMatPair() {sourceMaterial = mat });
}
}
}
mm.slices = newSlices;
}
string pth = AssetDatabase.GetAssetPath(mom.textureBakeResults);
string baseName = Path.GetFileNameWithoutExtension(pth);
string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
string matName = folderPath + baseName + "-mat" + k + ".mat";
Material existingAsset = AssetDatabase.LoadAssetAtPath<Material>(matName);
if (!existingAsset)
{
Material newMat = new Material(Shader.Find("Standard"));
// Don't try to configure the material we need the user to pick a shader that has TextureArrays
AssetDatabase.CreateAsset(newMat, matName);
}
mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
k++;
}
MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
textureBaker.Update();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8860927141262124c92c04030afa23d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MB_TextureBakerEditorConfigureTextureArrays.cs
uploadId: 797180
@@ -0,0 +1,19 @@
{
"name": "MeshBakerEditor",
"references": [
"MeshBakerLib",
"MeshBakerEditorLib",
"MeshBakerCore"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: dd9493fbefb52fd48926bb1291844728
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/MeshBakerEditor.asmdef
uploadId: 797180
@@ -0,0 +1,75 @@
using UnityEngine;
using UnityEditor;
public static class MeshBakerPurgeNullObjects
{
[MenuItem("Tools/Mesh Baker/Purge Null Objects From Selected Baker")]
public static void PurgeNullObjectsFromSelectedBaker()
{
GameObject selected = Selection.activeGameObject;
if (selected == null)
{
Debug.LogError("Aucun GameObject sélectionné.");
return;
}
Component[] components = selected.GetComponents<Component>();
bool foundList = false;
int totalRemoved = 0;
foreach (Component component in components)
{
if (component == null)
continue;
SerializedObject so = new SerializedObject(component);
// Nom utilisé par Mesh Baker pour la liste Objects To Be Combined
SerializedProperty objectsList = so.FindProperty("objsToMesh");
if (objectsList == null || !objectsList.isArray)
continue;
foundList = true;
int removed = 0;
// Important : on parcourt à l'envers pour supprimer sans décaler les indices restants.
for (int i = objectsList.arraySize - 1; i >= 0; i--)
{
SerializedProperty element = objectsList.GetArrayElementAtIndex(i);
if (element.propertyType == SerializedPropertyType.ObjectReference &&
element.objectReferenceValue == null)
{
objectsList.DeleteArrayElementAtIndex(i);
removed++;
}
}
if (removed > 0)
{
so.ApplyModifiedProperties();
EditorUtility.SetDirty(component);
totalRemoved += removed;
Debug.Log($"Mesh Baker : {removed} entrée(s) null supprimée(s) dans {component.GetType().Name}.");
}
}
if (!foundList)
{
Debug.LogError(
"Aucune liste 'objsToMesh' trouvée sur l'objet sélectionné. " +
"Sélectionne l'objet TextureBaker ou MeshBaker qui contient 'Objects To Be Combined'."
);
return;
}
AssetDatabase.SaveAssets();
Debug.Log($"Purge terminée. Total supprimé : {totalRemoved} entrée(s) null.");
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c2c6d03c5f9a6b441ae153812251dcad
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c307e366f91a4284d810409a68c5b7bc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,44 @@
using UnityEditor;
using UnityEngine;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
[CustomPropertyDrawer(typeof(ShaderTextureProperty))]
public class MB3_ShaderTexturePropertyDrawer : PropertyDrawer
{
public static GUIContent gc_isNormalMap = new GUIContent("isNormalMap", "This atlas texture will be marked as a normal map"),
gc_isGammaCorrected = new GUIContent("isGammaCorrected", "This atlas should be gamma corrected (sRGB checked). If not checked then the atlas will be a linear texture");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
float w = contentPosition.width;
contentPosition.width = w * 0.4f;
EditorGUI.indentLevel = 0;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("name"), GUIContent.none);
contentPosition.x += contentPosition.width;
contentPosition.width = w * 0.3f;
EditorGUIUtility.labelWidth = 50f;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("isNormalMap"), gc_isNormalMap);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, property.FindPropertyRelative("isGammaCorrected"), gc_isGammaCorrected);
//EditorGUILayout.PropertyField(property.FindPropertyRelative("name"));
//EditorGUILayout.PropertyField(property.FindPropertyRelative("isNormalMap"), gc_isNormalMap);
//EditorGUILayout.PropertyField(property.FindPropertyRelative("isGammaCorrected"), gc_isGammaCorrected);
EditorGUI.EndProperty();
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 24ced5fa006456249ac31e87abe5aa5b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/propertyDrawers/MB3_ShaderTexturePropertyDrawer.cs
uploadId: 797180
@@ -0,0 +1,65 @@
using UnityEditor;
using UnityEngine;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB_ConvertTextureArrayFormatWizard : ScriptableWizard
{
public Texture2DArray textureArray;
public TextureFormat format = TextureFormat.ARGB32;
[MenuItem("Window/Mesh Baker/TextureArray Format Converter")]
static void CreateWizard()
{
ScriptableWizard.DisplayWizard<MB_ConvertTextureArrayFormatWizard>("Convert Texture Array Format", "Close", "Convert");
}
void OnWizardCreate()
{
}
void OnWizardUpdate()
{
helpString = "Please assign a texture array";
}
void OnWizardOtherButton()
{
helpString = "";
if (textureArray == null)
{
helpString = "Please assign a texture array";
return;
}
MB3_EditorMethods editorMethods = new MB3_EditorMethods();
if (!editorMethods.TextureImporterFormatExistsForTextureFormat(format))
{
helpString = "No ImporterFormat exists for the selected format. Please select a different format.";
return;
}
if (textureArray.format != TextureFormat.ARGB32 &&
textureArray.format != TextureFormat.RGB24)
{
helpString = "Source TextureArray must be in format ARGB32 or RGB24. This will probably be changed in" +
"a future version of Mesh Baker.";
return;
}
Texture2DArray outArray = new Texture2DArray(textureArray.width, textureArray.height, textureArray.depth, format, true);
if (editorMethods.ConvertTexture2DArray(textureArray, outArray, format))
{
string pth = UnityEditor.AssetDatabase.GetAssetPath(textureArray);
if (pth == null) pth = "Assets/TextureArray.asset";
pth = pth.Replace(".asset", "");
pth += format.ToString() + ".asset";
UnityEditor.AssetDatabase.CreateAsset(outArray, pth);
Debug.Log("Convert success saved asset: " + pth);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d355da520c795f543a934da176eb59ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/propertyDrawers/MB_ConvertTextureArrayFormatWizard.cs
uploadId: 797180
@@ -0,0 +1,87 @@
using UnityEditor;
using UnityEngine;
namespace DigitalOpus.MB.MBEditor
{
public class MB_PaginatedList
{
public static void GenerateObjectsToBeCombinedList(SerializedProperty objsToMesh, ref int currentPage, ref int objectsPerPage)
{
SerializedProperty arraySizeProp = objsToMesh.FindPropertyRelative("Array.size");
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Size", GUILayout.Width(EditorGUIUtility.labelWidth));
int newSize = EditorGUILayout.DelayedIntField(arraySizeProp.intValue);
arraySizeProp.intValue = Mathf.Max(1, newSize);
if (newSize <= 0 &&
arraySizeProp.intValue == 1)
{
// This is necessary because the first element in the list gets preserved.
// If the user sets the number of elements to 0 or less then we should
// make the displayed first element == null
SerializedProperty element = objsToMesh.GetArrayElementAtIndex(0);
element.objectReferenceValue = null;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Objects per Page", GUILayout.Width(EditorGUIUtility.labelWidth));
EditorGUI.BeginChangeCheck();
int newObjectsPerPage = EditorGUILayout.DelayedIntField(objectsPerPage);
if (EditorGUI.EndChangeCheck())
{
objectsPerPage = Mathf.Clamp(newObjectsPerPage, 10, 500);
currentPage = 1;
}
EditorGUILayout.EndHorizontal();
int totalObjects = objsToMesh.arraySize;
int totalPages = totalObjects / objectsPerPage;
if (totalObjects % objectsPerPage != 0)
{
totalPages++;
}
if (totalPages == 0)
{
currentPage = 1;
}
else if (currentPage > totalPages)
{
currentPage = totalPages;
}
else if (currentPage < 1)
{
currentPage = 1;
}
int startIndex = (currentPage - 1) * objectsPerPage;
int endIndex = Mathf.Min(startIndex + objectsPerPage, totalObjects);
for (int i = startIndex; i < endIndex; i++)
{
SerializedProperty objProp = objsToMesh.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(objProp, new GUIContent("Object " + (i + 1)));
}
EditorGUILayout.BeginHorizontal();
GUI.enabled = currentPage > 1;
if (GUILayout.Button("Previous"))
{
currentPage--;
}
bool prevGUIEnabled = GUI.enabled;
GUI.enabled = true;
GUIStyle centeredLabelStyle = new GUIStyle(EditorStyles.label);
centeredLabelStyle.alignment = TextAnchor.MiddleCenter;
EditorGUILayout.LabelField("Page " + currentPage + " of " + totalPages, centeredLabelStyle);
GUI.enabled = prevGUIEnabled;
GUI.enabled = currentPage < totalPages;
if (GUILayout.Button("Next"))
{
currentPage++;
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 0eac7adb5e69eaa45b05407b27e84965
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/propertyDrawers/MB_PaginatedList.cs
uploadId: 797180
@@ -0,0 +1,82 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using DigitalOpus.MB.MBEditor;
namespace DigitalOpus.MB.MBEditor
{
/// <summary>
/// Draws rows for the PrafabPairs in the Switch Prefabs In Scene Window.
/// </summary>
[CustomPropertyDrawer(typeof(MB_ReplacePrefabsSettings.PrefabPair))]
public class MB_PrefabPairPropertyDrawer : PropertyDrawer
{
private GUIStyle redFont = new GUIStyle();
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
float xx = position.x;
float yy = position.y;
float ww = 15f;
float hh = position.height;
Rect enabledRect = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
xx += ww;
ww = 50;
Rect srcLabel = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
xx += ww;
ww = 200;
Rect sourceRect = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
xx += ww;
ww = 50;
Rect targetLabel = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
xx += ww;
ww = 200;
Rect targetRect = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(enabledRect, property.FindPropertyRelative("enabled"), GUIContent.none);
EditorGUI.LabelField(srcLabel, "Source:");
EditorGUI.PropertyField(sourceRect, property.FindPropertyRelative("srcPrefab"), GUIContent.none);
EditorGUI.LabelField(targetLabel, "Target:");
EditorGUI.PropertyField(targetRect, property.FindPropertyRelative("targPrefab"), GUIContent.none);
SerializedProperty errorsProp = property.serializedObject.FindProperty(property.propertyPath + ".objsWithErrors");
if (errorsProp.arraySize > 0)
{
redFont.normal.textColor = Color.red;
for (int i = 0; i < errorsProp.arraySize; i++)
{
xx = position.x;
yy = position.y + (1 + i) * EditorGUIUtility.singleLineHeight;
ww = 100;
SerializedProperty errProp = errorsProp.GetArrayElementAtIndex(i);
GameObject obj = (GameObject)errProp.FindPropertyRelative("errorObj").objectReferenceValue;
string errStr = errProp.FindPropertyRelative("error").stringValue;
Rect buttonRect = new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight);
if (GUI.Button(buttonRect, "Select"))
{
if (obj != null) Selection.activeGameObject = obj;
}
xx += ww;
ww = 500;
EditorGUI.LabelField(new Rect(xx, yy, ww, EditorGUIUtility.singleLineHeight), errStr, redFont);
}
}
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty errorsProp = property.serializedObject.FindProperty(property.propertyPath + ".objsWithErrors");
return base.GetPropertyHeight(property, label) + errorsProp.arraySize * EditorGUIUtility.singleLineHeight;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f8fdae7bfb5aa3a41ab365cd5a8238c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/propertyDrawers/MB_PrefabPairPropertyDrawer.cs
uploadId: 797180
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 31b5ad3e3da6e4244bdaa2a76ab994b6
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,39 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByAlreadyAdded : IGroupByFilter
{
public string GetName()
{
return "AlreadyAdded";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "alreadyAdded=" + fi.alreadyInBakerList;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
int alreadyAddedCompare = 0;
if (b.alreadyInBakerList == true && a.alreadyInBakerList == false)
{
alreadyAddedCompare = -1;
}
if (b.alreadyInBakerList == false && a.alreadyInBakerList == true)
{
alreadyAddedCompare = 1;
}
return alreadyAddedCompare;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: ac8e94c94918f5245823661062e06239
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByAlreadyAdded.cs
uploadId: 797180
@@ -0,0 +1,39 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByEnabledDisabled : IGroupByFilter
{
public string GetName()
{
return "Is Enabled";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return fi.go.activeInHierarchy ? "Enabled" : "Disabled";
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
int compareVal = 0;
if (b.go.activeInHierarchy == true && a.go.activeInHierarchy == false)
{
compareVal = -1;
}
if (b.go.activeInHierarchy == false && a.go.activeInHierarchy == true)
{
compareVal = 1;
}
return compareVal;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 000b6aa8344585d4fb87fb96b8149202
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByEnabledDisabled.cs
uploadId: 797180
@@ -0,0 +1,24 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByHasSameSetsOfMaps : IGroupByFilter
{
public string GetName() {
return "HasSameSetsOfMaps";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "HasMaps=" + fi.setOfMaps;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return a.setOfMaps.CompareTo(b.setOfMaps);
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 06dd0ff07a3ad5940af7018018361a3f
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByHasSameSetsOfMaps.cs
uploadId: 797180
@@ -0,0 +1,27 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_GroupByLayerIndex : IGroupByFilter
{
public string GetName()
{
return "Layer Index";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "layerIndex=" + fi.layerIndex;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return b.layerIndex - a.layerIndex;
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ce357bbdee02d3049a5ec6c026da0248
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByLayerIndex.cs
uploadId: 797180
@@ -0,0 +1,30 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByLightmapIndex : IGroupByFilter
{
public string GetName()
{
return "Lightmap Index";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "lightmapIndex=" + fi.lightmapIndex;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return b.lightmapIndex - a.lightmapIndex;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 8add88348b69079419318c17a4aec61a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByLightmapIndex.cs
uploadId: 797180
@@ -0,0 +1,29 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByMaterial : IGroupByFilter
{
public string GetName()
{
return "Material";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "material=" + fi.materialName;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return a.materialName.CompareTo(b.materialName);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 2ff3bf9d7e4fcb64eba007e5d54d5f6a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByMaterial.cs
uploadId: 797180
@@ -0,0 +1,31 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_GroupByMetallicOrSpecular : IGroupByFilter
{
public string GetName()
{
return "MetallicOrSpecular";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "metallicOrSpecular=" + fi.metallicOrSpecularName;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return a.metallicOrSpecularName.CompareTo(b.metallicOrSpecularName);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: fb37c235a0a0db442aa27cf27a99faeb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByMetallicOrSpecular.cs
uploadId: 797180
@@ -0,0 +1,30 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByOutOfBoundsUVs : IGroupByFilter
{
public string GetName()
{
return "OutOfBoundsUVs";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "OutOfBoundsUVs=" + fi.outOfBoundsUVs;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return Convert.ToInt32(b.outOfBoundsUVs) - Convert.ToInt32(a.outOfBoundsUVs);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 29fb03f40f7582c41a09dec611a68e8c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByOutOfBoundsUVs.cs
uploadId: 797180
@@ -0,0 +1,39 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByRenderType : IGroupByFilter
{
public string GetName()
{
return "RenderType";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return fi.isMeshRenderer ? "MeshRenderer" : "SkinnedMeshRenderer";
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
int renderTypeCompare = 0;
if (b.isMeshRenderer == true && a.isMeshRenderer == false)
{
renderTypeCompare = -1;
}
if (b.isMeshRenderer == false && a.isMeshRenderer == true)
{
renderTypeCompare = 1;
}
return renderTypeCompare;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: ccb4d2ba98c9989449e34934c09ec5ca
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByRenderType.cs
uploadId: 797180
@@ -0,0 +1,31 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByShader : IGroupByFilter
{
public string GetName()
{
return "Shader";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "shader=" + fi.shaderName;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return a.shaderName.CompareTo(b.shaderName);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 5f0f3a86ced986a4aa686551a1c3a4ad
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByShader.cs
uploadId: 797180
@@ -0,0 +1,39 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class GroupByStatic : IGroupByFilter
{
public string GetName()
{
return "Static";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "isStatic=" + fi.isStatic;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
int staticCompare = 0;
if (b.isStatic == true && a.isStatic == false)
{
staticCompare = -1;
}
if (b.isStatic == false && a.isStatic == true)
{
staticCompare = 1;
}
return staticCompare;
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 4e91e5646c425c8428d175ac3fe62800
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByStatic.cs
uploadId: 797180
@@ -0,0 +1,31 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using DigitalOpus.MB.Core;
namespace DigitalOpus.MB.MBEditor
{
public class MB3_GroupByTransparency : IGroupByFilter
{
public string GetName()
{
return "Transparency";
}
public string GetDescription(GameObjectFilterInfo fi)
{
return "transparency=" + fi.standardShaderBlendModesName;
}
public int Compare(GameObjectFilterInfo a, GameObjectFilterInfo b)
{
return a.standardShaderBlendModesName.CompareTo(b.standardShaderBlendModesName);
}
}
}
@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: b9be5ed7795b65d448a3cd700e472f8a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Editor/searchFilters/MB3_GroupByTransparency.cs
uploadId: 797180
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3290cf8f3944293438cfe8df22e4af7f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,83 @@
fileFormatVersion: 2
guid: 0f32008f8aab7e54f86387d6790b2c02
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 0
Exclude Linux64: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Libs/MeshBakerEditorLib.dll
uploadId: 797180
Binary file not shown.
@@ -0,0 +1,40 @@
fileFormatVersion: 2
guid: cab42632cbdacc94f9b261da366ec4c4
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/Libs/MeshBakerLib.dll
uploadId: 797180
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 96adfa24818e71649adf8d4741021058
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1 @@
The MeshBakerWorkingFolder is used to store temporary assets created by Mesh Baker during bakes. This file exists so that this folder doesn't confuse source control systems which don't track empty folders.
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 4bdd3f9a90a7923428f5dedc4d223593
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/MeshBakerWorkingFolder/DONT_DELETE.txt
uploadId: 797180
+35
View File
@@ -0,0 +1,35 @@
MeshBaker is a tool for combining many meshes into one big mesh and creating texture atlases
from all the textures used by the source meshes. OBJECTS TO BE COMBINED DO NOT NEED THE SAME
MATERIAL OR EVEN THE SAME SHADER. Meshbaker will create empty textures and resize copies of
textures if needed to build the atlases. Meshbaker does not touch the source assets
(other than setting the read flag on textures). It bakes the source
assets into new assets which can be used in your scene for high performance scene loading.
QUICKSTART
MeshBaker is best used in the Unity Editor (see below for runtime use)
Create a new MeshBaker object in your scene under the Game Object menu.
Game Object
-> Create Other
-> Mesh Baker
-> MeshBaker
Follow the instructions in the inspector.
See "Manual.pdf" for more information.
Latest tutorial videos are found in this youtube list: https://www.youtube.com/playlist?list=PLCzm-udM-shlRUy5f9QHHxqqv-9wP5FBM
UPGRADING FROM THE EVALUATION VERSION
To upgrade from the evaluation version, delete the MeshBaker folder from
your project and import the full version.
Note that after doing this you may have "Missing Script" errors on your Combined Material assets.
These can be fixed by clicking on the circle with dot in it beside the "Missing Script" text in the
inspector and choosing "MB2_TextureBakeResults" from the list of scripts.
SUPPORT
Please post to the forums at https://discussions.unity.com/t/mesh-baker-by-digital-opus-released/490738/3694
email: contact.digitalopus@gmail.com
+9
View File
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: eb65045eaa0d32a41804f69da7d5eec3
AssetOrigin:
serializedVersion: 1
productId: 31895
packageName: Mesh Baker Free
packageVersion: 3.40.1
assetPath: Assets/MeshBaker/README.txt
uploadId: 797180
+851
View File
@@ -0,0 +1,851 @@
Version 3.40.1 September 30, 2025
Fixed error loading groupers in analyse scene tab.
Version 3.40.0 Septembr 5, 2025
Added namespaces for the example scripts and made namespaces more consistent.
GameObject.FindObjectsOfType replaced by MBVersion.FindSceneObjectsOfType
MeshBakerEditor:
Added SaveMeshAsAsset button
Added Pagination
TextureBakerEditor:
Added Pagination
MeshBakerWindow Add Objects Tab:
Added Opacity filter:
Added lightmap values:
Added layerMask:
MeshBakerWindow Analyse Scene Tab:
Sets of Maps
layer index
Transparency works for URP
URP/HDRP surface type
MeshBakerGrouper:
parent scene object gets used if it has been set.
UnwrapUV2
Tries to detect if the unwrap has failed and switches the indexing if it did.
Added URPUnlitTextureArray shader.
Version 3.39.0 August 20, 2024
Group By filters: switched StandardRenderMode to "Opaque or Transparent" which now uses RenderQueue instead of shader properties.
Group By filters: added Metallic or Specular filter to filter by URP and Standard shader workflow.
TextureArrays fixed bug in recent Unity versions where temporary textures created with dim 4096 would be imported as 2048 and Graphics.CopyTexture would fail.
Changed the texture array NormalMap shader so that it swizzles the color channels for platforms that support DXT compression.
Fixed bug using TexturePackerFast and normal maps so that it swizzles the color correctly.
Added step: ConfigureResultMaterialKeywordsIfNecessary because URP materials need keywords set when baking at runtime or they don't work properly.
Better handling of ColorSpace if user is using Linear color spaces.
Version 3.38.0 July 27, 2024
Removed some code for Unity 5 and earlier
Added a tool (window) for generating and assigning solid color textures from color tints for source materials.
Fixed bug where Unity 6 version is not recognized properly. To do this replaced GetMajorVersion and GetMinorVersion with Is_2017_1_OrNewer & Is_2018_3_OrNewer
Fixed bug where MeshCombinerSingle.bufferDataFromPrevious bake was not serialized.
Fixed bug when deleting objects from a previous bake where GameObject IDs change between edit mode and playmode
Removed gameObjectID from blendShape since it is not stable between edit mode and playmode
Added error when we can't match a source material with baked materials and source materials contain the work "Instanced"
Improved working with Multiple Material mappings:
Can move a sourceMaterial up and down the list of mappings
Can move mappings up and down
Can insert a mapping in the list of mappings
Can create a combined material for a mapping
Improved color space handling for linear color spaces
Added method MBVersion.IsTexture_sRGBgammaCorrected()
Version 3.37.0
Mesh Baker now supports two Mesh APIs "Simple Mesh API", "(beta) Native Array API"
The Native Array API is usually faster. Most future development will happen on the NativeArray API.
MeshBakerGrouper added undo functionality to the operations
MeshBakerGrouper made multi-editable
Mesh Baker Window Analyze Scene Tab pagination
TextureBlenderURPLit: fixed so it works for Lit, Simple Lit, Baked Lit, Unlit, Complex Lit, Particles Lit, Particles Simple Lit, Particles Unlit
Moved BlendShape combiner code into MB_MeshCombinerSingle_BlendShapeProcessor.cs
Fixed bug with BoneProcessor when adding meshes and creating no new bones.
TextureArrays
Added a new interface for IAssignToMeshCustomizer_NativeArrays
Added bakeStatus to MeshCombinerAPI
Renamed some MeshCombinerSimple files to use convention MB_MeshCombinerSingle_XXX
New example scene demonstrating how to create a simple solid color block atlas without using the TextureBaker
Fix inspector lists that display first element overlapping in Unity 2021.3+
In tools for adding objects added filter for opaque vs transparent
Version 3.36.1 June 8, 2023
Fix build error
BatchPrefabBaker null checks
Version 3.36.0 June 5, 2023
** Important ** The clear buffers after bake behaviour has changed. It may be necessary to uncheck
"Clear Buffers After Bake" if you are baking repeatedly.
Changed "clear buffers after bake" feature so that buffers are cleared when "Apply" is called. Previously this only happened when editor buttons were pressed.
Fixed typos in some of the text in the inspector and error messages.
Fixed exception when there are zero rows in inspector and we press the delete row button.
Fixed NullReferenceException if there is a null material when using "Configure Multiple Materials From Objects To Be Combined".
Updated MeshCombiner to use new Unity Mesh API for setting and getting BoneWeights.
Better validation and error handling when baking skinned meshes.
Added EncodeToTGA so that it is possible to save atlases in TGA format.
Fixed display of TextureShaderProperty.
Some lists don't display properly in Unity 2021. The first row is overwritten. Fixed by adding [NonReorderable].
MeshCombiners implement the IDisposable interface and are Disposed in OnDestroy.
Apply and UpdateGameObjects return a bool to indicate success or failure.
Added function MBVersion.IsAssetInProject(Object).
Added interface MB_IMeshCombinerSimpleBones to better encapsulate functionality for processing bone data in skinned meshes.
Version 3.35.1 Sept 16, 2022
Added ASMDEF file to Examples folder. This fixes compile errors if the MeshBaker folder is added to a folder that has an ASMDEF
Fix error "Could not find a tiling rect..."
Fix Blend-Non-Texture-Properties bug when there are no textures, only color tints.
Created TEMP_SOLID_COLOR_TEXTURE_SIZE constant.
Version 3.35.0 July 26, 2022
Fix bug where parentSceneObject can loose its reference.
Made MAX_ATLAS_SIZE a constant so it is easy to update.
Added a TextureBakerEditorInternal.isCombiningTexture variable so other scripts can detect if texture baking is in progress.
Added TextureCompressionFormat to MB_TextureArrayFormat.
Correct handling of TextureFormat.CompressionQuality.
Updated TextureBlenders for Standard and URP to handle alphaClipping
Refactored MeshCombinerSimple so that combining functions are handled by a separate class. This is a first step toward migrating to NativeArrays
Fix bug with URP texture tiling where material tiling was only being applied to BaseMap. This is encapsulated in ShadersThatShareTiling.cs
Version 3.34.3 Mar 10, 2022
Fix serializing lightmapping after using the "Preserve Current Lightmapping" and saving the scene.
Fix "Preserve Current Lightmapping" when source meshes do not have a UV2 channel
Fix "Find Objects In Scene" window so that it is possible to find objects using lightmap Idx 0 & 1
Version 3.34.2 Jan 21, 2022
Fix bone index problem with the BoneWeightCopier
Fix TexArray code so that it is possible to create TextureArrays at runtime
Move the MeshBakerGrouper grouper functions from the editor side to the runtime side so that it is possible to do grouping at runtime.
Version 3.34.1 Aug 10, 2021
Fix "d3d11: buffer size can not be zero" error when baking skinned meshes using 2019.4.28+
Fix where URP bakes would create unused _MainTex atlas
Version 3.34.0 July 28, 2021
Added list of texture properties to ignore to the TextureBaker settings
When Batch Prefab Baker creates result prefabs. It will check if they exist and create new ones instead of overwriting them.
Added ContextMenu command to all bakers for purging nulls from list of objects to combine.
Added TextureBlender for HDRP
Fix bug where I was using SerializedProperty.enumValueIndex where I should have been using SerializedProperty.intValue.
Version 3.33.2 Apr 19, 2021
Fix errors with BatchPrefabBaker with some versions of Unity
Fix error where combined scene object would not be parented when calling Apply
Added OptimizeMesh function that works in all versions of Unity
Fix NRE error when dragging a GameObject that doesn't have a MeshBakerGrouper to the MeshBaker.SharedSettings field
Fix deprecated feature warning for optimize mesh in 2019+
Fix typos in UI tooltips
=================
Version 3.33.1 Mar 7, 2021
Bug fix for build error caused by MigrateMaterialsToDifferentPipeline. Added #if UNITY_EDITOR
=================
Version 3.33.0 Feb 18, 2021
Mesh Baker works with Addressables when materials are baked in the editor but Meshes are baked at runtime and loaded from bundles. This
had been a problem because materials in the TextureBakeResult wouldn't map to rectangles in the atlas.
Switched serialized path in the BoneWeightCopier to be Assets folder relative and standardized path browsing UI.
Example scenes work better with HDRP and URP. There is now a script that will detect the pipeline and auto update each example scene.
Fixed example "bake textures at runtime" scene so that it choses an appropriate shader for the pipeline.
Fix spelling and grammar in tooltips
Fix obsolete prefab API warnings in 2017+
=================
Version 3.32.0 Nov 3, 2020
Can handle skinned meshes with blend shapes but zero bones
Paths to project assets folders are now stored relative to the Assets folder
Fixed bug with BatchPrefabBaker Prefab Rows not being initialized to zero length for new bakers
Fixed bug with GroupBy Standard Rendering Mode so that it works with URP and HDRP
Updated instructions for Batch Prefab Baker
Added an optional field to MeshBaker & MultiMeshBaker 'Parent Scene Object' baked combined meshes will be children of this.
Bake Into Prefab improvements
Can leave instance in scene after bake
There is button for creating empty prefabs. This works with multi object editing.
Mesh Baker Grouper can set up bakers to "Bake Into Prefab"
Mesh Baker Grouper improvements
Added option to "Auto Generate Prefabs"
Added folder field where prefabs will live
If using this option then generated combined meshes will be prefabs
=================
Version 3.31.0 June 15, 2020
Better handling for linear color space projects.
Added TextureBlenderURP for the Universal Render Pipeline/Lit shader
Improved collecting texture properties from result material. Was using the Material
API which was bad because it remembers extra properties from old shaders if the shader
is switched. Now collect the texture properties using the Shader API instead.
Bug Fix: Fixed some bugs in the the Standard shader texture blenders.
Bug Fix: NRE when trying to use listShadersInScene and with split into groups.
Bug Fix: When trying to combine skinned mesh renderers that are not prefab instances,
bones would not always be copied correctly to the prefab. Fixed.
Bug Fixs For Texture Arrays:
Fixed error generated when trying to assign platform spcific texture formats
to the default platform.
Fixed errors when generating solid color textures in platform specific formats.
Fixed errors caused by linear color space textures.
=================
Version 3.30.3 May 6, 2020
No functional changes. The previous version included two packages of examples for the HDRP and URP pipelines. These increased the package size by 100 meg
This release switches those packages to include only Materials which reduces the increase to 2meg.
=================
Version 3.30.1 May 6, 2020
Fix compile error due to HDRP APIs not being properly shielded.
=================
Version 3.30.0 Apr 24, 2020
New feature, MeshRenderers can be baked with SkinnedMeshRenderers without the addition of new bones if the MeshRenderer is a child of a SkinnedMeshRenderer bone.
New feature, BlendShapes in different SkinnedMeshRenderers can be merged when combining if they have the same names. This is useful when baking different body parts.
New feature, New version of TexturePackerFast which works with HDRP, URP and Default pipelines.
Fix compile error due to API changes in Unity 2020
Change, Mesh Baker does not overwrite changes to the combined material for texture properties that do not exist in any of the source materials.
=================
Version 3.29.1 Feb 18, 2020
Bug fix when updating a combined skinned mesh. Some bones that are unused should have been deleted that were not.
Combined all the bone processing code into a class so it is easier to manage
Freshly created MeshBakerGroupers may not have Settings instantiated. This can result in NRE if user tries to Bake without first visiting baker in the inspector.
Fixes to the MeshBakerSettings where RenderType was sometimes used from the MeshCombiner when it should have been read from the MeshBakerSettings
Split the MeshBakerWindow into a separate class for each tab and a class for the window and improved Undo.
Fix for adding disabled objects in the hierarchy to the Objects To Combine
Fixed issue where inactive renderers are not replace when using the Batch Prefab Baker
CollectTextureProperties uses the Material API to get the properites from the material for Unity > 2018.2
Made the MeshBaker and MultiMeshBaker buttons work with MultiObjectEditing.
Made TextureArray buttons work with MultiObjectEditing.
Removed CanEditMultipleObjects from BoneWeightCopier
Modified MeshBakerGrouperEditor so that it supports MultiObjectEditing.
Fixes NRE with batch prefab baker.
Fixed bug where textures are converted to ARGB32 when they should be RGBA32 on Unity 2019.
Better warning when TexturePacker exceeds max recursion depth, explaining why and what to do.
Fix bug where SkinedMesh bake would faile the first time.
Changed the workflow for SkinnedMeshRenderer Bake Into Prefab. Mesh Baker now does the bone copying. This was very tricky with the new Unity Prefabs.
=================
Version 3.29.0 Oct 20, 2019
Added Beta support for Texture Arrays
Can choose to bake into atlases or Texture Arrays
Can define multiple output formats. Texture Arrays will be baked for each format
Can configure which source materials will be baked into which slice
Slice Index can be baked into a coordinate of the mesh
An example shader is included
Manual for Texture Arrays
Fixed issue with normals for meshes with negative and non-uniform scaling
Fixed issue with "Replace Prefab Instance In Scene Window", model prefabs would not be replaced properly.
Added option for setting a custom mesh pivot.
Added property names Lit shaders used by HDRP and LRP
Added extra UV channels (5,6,7,8) added in recent versions of Unity
=================
Version 3.28.1 July 8, 2019
Added a "Replace Prefabs In Scene Window". This is useful for switching prefabs in the scene with the optimized versions created with the Batch Prefab Baker.
Fix bug with Skinned Mesh bones error that would prevent updating combined skinned meshes if source meshes shared bones.
Configure newly created Mesh Bakers so they use the settings from the MeshBakerGrouper.
Added workaround for bug in 2018.X where a SerializedObject for a prefab would become corrupt when the prefab is instantiated.
Fixed formatting for many documents.
Added a namespace (DigitalOpus.MB.MBEditor). Editor scripts have been added to this namespace.
=================
Version 3.27.3 June 18, 2019
Fixed issue with Blend Shapes not working in the recent versions of Mesh Baker.
Changed how the BlendShapes 2 Combined map is handled. A component containing the serialized map data is added
to the combined mesh. This makes it easier to save the map as part of a prefab without needing to save the MeshBaker component.
Fixed error when saving into prefabs using 2018.3+
=================
Version 3.27.2 June 4, 2019
Fixed bug where using UnityEditor is included in MeshBakerGrouper which breaks building for export
Added new example scene that existed in the 5.x version but was missing in 2017 version
=================
Version 3.27.1 May 7, 2019
Added a MeshBakerSettings Scriptable object that can be shared my many MeshBakers and MultiMeshBakers and the MeshBaker Grouper.
MeshBakerGrouper applies the same shared settings to all generated mesh bakers
Added ability to delete existing mesh bakers and combined meshs
When re-generating clusters the meshBakerGrouper automatically deletes existing bakers and combined meshes
Fixed bug where normals were not being scaled correctly for meshes with non-uniform scale
Fixed bug when using the standard shader if different maps had different tiling
=================
Version 3.26.3 March 19, 2019
Fix bug with MeshBakerFast texture packer where textures could be copied to atlas upside down on some platforms.
Add code to delete runtime created meshes when switching scenes.
Changed how Mesh Baker serializes references to game objects. Instead of using Instance ID a reference to a game object is used.
This fixes issue where meshes baked in the editor cannot be modified at runtime.
==================
Version 3.26.2 December 19, 2018
Add Drag & Drop target box when adding objects to be combined.
Fix bug when using TextureBaker, multiple materials and trying to split the result into multiple
atlases which did not work.
Fix issue when using Texture Packer, Mesh Baker Fast on Metal platform where atlases would be upside down.
Fix issue where UpdateGameObjects would not work correctly if the material was switched on the source game object.
Move Editor scripts into a folder that is not a subfolder of the Scripts folder. This was necessary
so that assembly definition files and the Unity test runner will work in Unity 2018.
Split the MB3_MeshCombinerSimple class into multiple files because it was very large.
Added an example scene and script for switching a material on a source object and updating the combined mesh.
==================
Version 3.26.1 October 30, 2018
Upgraded to version 5.5.1 and regenerated all textures.
This was necessary to fix issues where Unity 2018.3 could
not read assets generated with older versions of Unity.
==================
Version 3.26 July 17, 2018
Fixe for NRE when using MeshBaker packer and null textures
Fix bug for missing build target Tiezen in 2018.2
Fix bug importing PVRT compressed meshes which don't support GetPixelBilinear
Added search filter for LOD levels
Introduced maxAtlasWidth and maxAtlasHeight which can be set independantly for horizontal vertical packing
Added horizontal vertical texture packing
BatchBakerPrefab changes
Fixes bug where more materials could be assigned than submeshes
Baked meshes are saved as part of the prefab
Bake does a better job of cleaning up unused materials
Added a bake that only updates meshes and materials
Added log level
==================
Version 3.25 April 26, 2018
Created a TextureBlender for MetallicRoughness
Rewrote the texture blenders for MetallicSpecular and Metallic
Fixed bug with only one texture in atlas if textures for different properties had different tiling.
Added non texture property average classes so that an average value can be used if not using consider non texture properties
Fixed issues iwth blending non texture properties with the Standard shader.
Refactor
Cleaned up creating of temporary textures used in atlas creation. They are not created on a per atlas basis immediately before use and disposed of immediately afterward.
Created TextureCombinerPackerOneTextureInAtlas for handling the case of only one texture in atlas.
Removed code from other TextureCombinerPackers for handling one texture in atlas cases.
==================
Version 3.24.3
Removed references to Procedural Texture which were removed in Unity2018
==================
Version 3.24.2
Support for meshes larger than 64k
Big refactor of the texture combining pipeline
==================
Version 3.24.1
Rewrite of the TextureBlenderStandardMetallic
Fix bug where mesh was not assigned to prefab when generating skinned meshes with the MultiMeshBaker and assigning to a prefab
Refactored Texture Combining pipeline.
Refactored BlendTextureProperty system. Encpsulated code in a separate file.
Replaced simple bool allTexturesAreNullAndSameColor flags with more informative CreateAtlasForProperty
Fixed problems when merging atlas rectangles that would occasionally generate strange UV map problems
Moved everything related to atlas merging into its own file
==================
Version 3.24.0
Fixed bug where normal map format is not restored if texture is uncompressed
Added TexturePackerHorizontal, TexturePackerVertical which stack textures in atlas so that textures in atlas can tile horizontally and vertically
Removed creation of report when using list shaders in scene
==================
Version 3.23.3
Fixes error when baking skinned meshes in Unity 2017.2. that generated error about skinned meshes lacking skinning information.
==================
Version 3.23.2
Added integrity check to TextureCombiner so it checks if can find tiled rect after generating atlas
Fixed bug combining materials that have different tiling on different maps when using 'consider UVs' that would generate 'can't find tiled rectangle' error
Fixed bug when baking skinned mesh prefabs where prefab would not be built and scene object was destroyed making it impossible to add bones
Fixed bug when building for Android or Tizen and ASTC compression that would cause pixelated quality in atlases
==================
Version 3.23.1
Baking children for a grouper now works correctly if there is no TextureBakeResult
Fixed errors using Unity 2017 with Crunch compression
Fixed errors using when baking objects with different materials and no TextureBakeResult
Fixed bug that caused TextureBlenders to use Fallback when other blenders match shader
==================
Version 3.23.0
Improved 'Consider Mesh UVs' can now be applied with different value to each result material
Added version number to TextureBakeResults to fix backward compatibility issues.
Refactored TextureBakeResults so that only resultMaterials is used in all cases. _resultMaterial is depricated
Fixed bug with Unity 5.4 + with TexturePacker.MeshBakerTexturePackerFast creating black textures
Fixed bug with MeshBakerGrouper so that it will include bakers with only one source object if desired
_MetallicGlossMap color if no texture is 0,0,0,1 to fix issues with alpha=0 in map
Fixed bug when using GroupByStandardShaderMode which would not compare correctly
Added write texture to TGA code (not yet integrated with UI)
Refactored "Build Source To Combined Mapping" to use new Consider Mesh UVs
==================
Version 3.22.2
Fixed bug where submeshes with zero length triangle arrays could be created causing dynamic batching errors
Fixed bug where submesh triangles not being serialized correctly and causing errors with ShowHide
Fixed auto generation of multiple materials to handle standard shader modes
==================
Version 3.22.1
Fixed bug where many submeshes were created if no TextureBakeResult and all source objs share a material
Fixed bug where UV2 could contain NAN values if using 'copy UV2 to separate rects' and a source mesh has no UV2 channel.
Refactored platform defines so they all exist only in the MBVersion
==================
Version 3.22
Fixes so Mesh Baker will work with Unity 2017
`
==================
Version 3.21
Modified texture packer to support distributing textures across multiple atlases if total packing exceed atlas size
Editor window can split atlases when listing shaders in scene
Texture Baker can distribute across atlases when using the multiple materials feature
==================
Version 3.20
Added include cells with only one renderer checkbox to MeshBakerGrouper
Changed clustering to use render bounds center instead of gameobject pivot
Fixed drawGizmos for pie clusters so it matches what is clustered
Made agglomerativeClustering cancelable
Massive performance improvment for agglomerativeClustering
Fixed bug with blendshapes if more than one blendshapes
Fixed TextureCombiner indexOutOfBounds that occurs if the shader has no texture properties
==================
Version 3.19.5 May 26, 2017
Fix bug in Unity 5.5+ which generated a compile error in import.
==================
Version 3.19.4 May 19, 2017
Cleaned up Mesh Baker Menu
Added link under Windows for opening Mesh Baker window
Changed numbering of newly created bakers to match Unity's convention
Renamed 'Material Bake Result' to 'Texture Bake Result'
Set the MeshBakerGroup default algorithm to 'Agglomerative' and improved default settings
MeshBakerGrouper detects if there are already child bakers with objects in list of objects to combine
Set default _considerNonTextureProperties to false to speed up atlas creation
Fixed NullPointerException when running texture bake as a Coroutine on a platform that doesn't support it
Optimize after bake is never called at runtime
Updated Manual & API docs
==================
Version 3.19.3 March 27, 2017
Added #IF UNITY_EDITOR to mesh optimization code since it uses UnityEditor. Fixed build error
Added fix for rounding error with Vector2 which could cause "Cannot find merged rectangle" errors
Added fix for builing for WAS, reflection classes don't exist
==================
Version 3.19.2 March 13, 2017
Fixed bug with blend shapes if using the same Mesh Baker multiple times
Fixed bug with GroupByFilterStandardShaderMode so groups correctly
Fixed bug if using a mesh with no UVs and using the 'consider UVs' feature would get Can't find merged rect error
==================
Version 3.19.1 Febuary 15, 2017
Fixed bug with creating temporary bake results
Added conditional version code for LOD groups only for 5.1 and greater
Added conditional version code for mesh.Optimize for 5.6 and greater
Speed up for agglomerativeClustering
==================
Version 3.19 December 31, 2016
- Modified 'can bake without baking textures first'. Now collects all materials and maps each mat to its own submesh
- Removed limitation where first mesh must have all materials
- Fixed bug with MeshCombiner checking objsInCombined list if user has deleted some of these
- Batch Prefab Baker calls .ClearMesh before trying to bake so combiner isn't contaminated by previous bakes
- TextureCombiner creates temporary textures for missing textures earlier in the pipeline. Fixes bugs with
consider mesh UVs if some materials don't have textures.
==================
Version 3.18 December 8, 2016
- Agglomerative clustering
- Fixed error when no clusters.
- Add button to trigger creating clusters.
- Add progress bar
- Added feature for recenter verts to bounds center
- Fixed bug when deleting parts of combined mesh would leave bones
- Added optimize after bake
- Batch prefab baker will create new meshes if targets are same as source.
- Can use tools for adding objects to remove objects from bakers in a bulk operation
- Cluster grouper can group by LOD level
==================
Version 3.17 November 22, 2016
- New Agglomerative cluster type in the MeshBakerGrouper
- Performance improvements when adding and deleting bones. Uses HashSets instead of traversing lists
- Added a "select objects to be combined" convenience button
- Added ability to sort objects to be combined along an axis. Usefull for transparent shaders
- Can populate rows in batch prefab baker from prefab instances in scene
- A number of minor fixes
==================
Version 3.16.3 October 25, 2016
- Added regular expression field for filtering game objects to be added in the add objects to bakers window
- Fixed bug with "list shaders in scene" which generate exceptions if a file is modified
- MeshBakerGrouper does not create bakers if there are no objects or only one object in a cell
==================
Version 3.16.2 October 8, 2016
- Added support for the new Texture Import API in Unity 5.5
==================
Version 3.16.1 September 16, 2016
- Added support for blend shapes
- Mesh Baker can now convert 'optimized' meshes to be readable
- New UV2 option. If source objects have custom UV2 layout, this can be preserved when copying to combined mesh
==================
Version 3.16.0 September 6, 2016
- Fixed bug with "Open Tools For Adding Objects" window. Texture baker tab would hang.
- Fixed Bake Meshes in Place Bug if folder path is not set and bake is clicked
- Fixed bug where MeshBakerGrouper bug can include renderers not in texture baker
- Converted texture baking to a coroutine so texture baking at runtime can take place across several frames.
- Fixed bug and refactored the _considerUVs option that merges textures.
===================
Version 3.15.1 August 18, 2016
- Fixed bug preventing MultiMeshBaker from displaying.
===================
Version 3.15.0 August 9, 2016
- Fixed bug with merge overlapping textures where textures would map to wrong parts of the atlas.
- Cleaned up variable naming in merge overlapping textures code
- Refactored merge overlapping textures
- Added fields to MB3_TextureBakeResults for samplingEncapsulatinRect, sourceMaterialTiling, samplingRectMatAndUVTiling, srcObjName
- Improved comments in the code.
- Removed unused variable references to get rid of warnings.
====================
Version 3.14.0 July 15, 2016
- Added multi object editing support to the MB3_MeshBaker and MB3_TextureBaker
- Added support for TextureBlenders to provide better blending of non-texture properties such as _Color with textures
- Updated the manual
====================
Version 3.13.1 April 27, 2016
- Added button to the batch prefab baker to automate creating prefabs
- Improved the BoneWeightCopier script to copy normals, position and tangent as well.
=====================
Version 3.13.0 April 13, 2016
- Changed Fix out of bounds UVs to 'Consider Mesh UVs'
- Added candy striping to multiple materials section of the inspector
- Changed 'Consider Mesh UVs' so it works for UVs that are not out of bounds. Only parts of source textures that are used are copied to atlas
- Added a feature for Merging UV rectangles in the atlas if the source rectangles overlap and it would be more efficient to use a combined
rectangle than two separate rectangle
======================
Version 3.12.3 Feb 20, 2016
Fixed bug where GroupBy filters are not found if an assembly cannot be loaded
Added UV2 unwrapping parameters to user interface.
Fixed bug with multiple materials and out of bounds UVs doesn't work if "out-of-bounds-uvs" is checked.
======================
Version 3.12.2 Dec. 9, 2015
- Fixed bug with the Mesh Baker Grouper. It was adding multiple objects multiple times which created errors when baking.
- Added button to the batch prefab baker to automate creation of result prefabs.
======================
Version 3.12.1 Nov. 20, 2015
- removed two references to UnityEditor in the runtime scripts and a variable not used warning.
======================
Version 3.12.0 Nov. 20, 2015
- Mesh Combiner API now handles combining objects with no Texture Bake Result if all objects use the same material
- Bones are not duplicated in bones array if bones are shared.
- Updated TextureCombinerFast shaders. These ones work much better
- Fixed bug with TextureCombinerFast normal maps being converted to Unity format twice
- Added UV3 and UV4 channels for Unity 5
- Added a script for applying same bone weights to the seams of skinned meshs to make customization of character meshes easier
======================
Version 3.11.1
- Fixed bug using Mesh Baker without first baking textures that caused materials to be Instanced.
======================
Version 3.11.0
- Includes a new Mesh Baker Texture Packer Fast option to pack textures on using the GPU instead of the CPU
======================
Version 3.10.3
- added a MaxAtlas size field to replace the code that tried to predict based on platform
- added code to grabe the _Color property from the first material
======================
Version 3.10.2
- Fixed bug preserve lightmapping.
======================
Version 3.10.1
- Fixed serious bug where meshes with tiling UVs would not be detected
- Modified editor functions so it is easier to customize bake behaviour
======================
Version 3.10
- Improved handling of missing textures in Standard shader. Much better code for choosing reasonable colors
- Fixed typo on "Search For Meshes" tab
- Increased the size of space in atlas for missing textures to 16x16 to help with color bleeding
- Fixed missing SpecGlossMap in names to look for
- Fixed bug where tag and layer are not set the first time objects are added to a baker
======================
Version 3.9
- Meshes are cached after being analyzed improves performance
- Added group by option for already added to baker
- Added filter option for already added to baker
- Mesh Baker tries to use a default color if there is no texture
- Fix so Mesh Baker works from plugins folder
- Fix for outOfBoundsUVs report false positive
======================
Vesion 3.8.1
- Minor fix stops errors creating new baker caused by uneeded debug statement.
======================
Vesion 3.8
- Fixed bug setting normal map for _Normal and _DetailBumpMap
- Can set normal map treatment for custom shader properties
- Can easily add custom filters to the group by
- Doesn't create atlas if all source textures are null
- Progress bar for list material in scene report
======================
Version 3.7.4
- Fixed bug with mesh baker on its own game object
- Fixed bug generating assets using tools for adding objects
======================
Version 3.7.3
- Refactored the tools for adding objects window so it is much more flexible and can create bakers directly
- Added texture property names to support the new standard shader.
======================
Version 3.7
- Fix for tiny images being scaled to zero when atlas is larger than maximum size
- Fix for auto generate mesh bakers bug not finding the Mesh Baker
- Can be configured to produce only power of two textures
======================
Version 3.6.1
- Bug fixes for Unity 5 compatible
======================
Version 3.6
- Updated to be compatible with Unity 5
======================
Version 3.5.1
- Added gizmos to the MeshBakerGrouper
- Added button to bake all child MeshBakers of a MaterialBaker
- Added button to disable renderers of child material baker
- Fixed bugs where multi-mesh bakers would not bake when baking all bakers.
======================
Version 3.5
- Added the MB3_MeshBakerGrouper component
- Removed many of the default arguments from the example scripts which caused build errors on iOS
======================
Version 3.4.1
- Fix bug with IndexOutOfBounds exception when baking without TextureBakeResults
- Fix NullPointerException when no objects in list of objs to combine
- Added warning when buffers have been cleared and no objects in instance2combined map
======================
Version 3.4
- Border color of textures in atlas bleed into the padding. Fixes problems with mipmaps picking up padding color
- Can bake objects without creating an atlas as long as they all use the same set of textures.
- Better memory allocation when creating atlases.
- Added MB3_DisableHiddenAnimations to disable animations that are not playing
- Added checkbox to clear buffers in baker after bake. It is rare that a user would want the buffers.
======================
Version 3.3.1
- Fixed bug when user uses a prefab asset in the result scene object field
- Displays error if user tries to bake a mesh that has read/write = false
======================
Version 3.3
- Fixed a bug where list of objects to combine produced null pointer exception
- Added BatchPrefabBaker
- Generated normal maps (when no normal on source) are now neutral normal color
======================
Version 3.2.1
- Fixed bug where creating source to combined mapping for multiple materials would add source mat multiple times
- Added several examples and explantions with other Examples
- Optimization where uvs are not adjusted if there is only one texture in the atlas
======================
Version 3.2
- Fix error creating new bakers
- Fix error baking into prefab if have not baked scene object first.
======================
Version 3.1
- Hides debug statment in multi-mesh-combiner
- Sets default size of texture combiner to 2048
- Removes references to legacy scripts in MB2_UpdateSkinnedMesh scripts.
======================
Version 3.0
- Big refactor to simplify code.
- Cleaned up API
- removed a number of unecessary parameters from function calls
- Made method names more consistant
- More code is shared between MeshBakerCommon and subclasses
- Mesh combiners inherit from a proper superclass
- Handles objects with negative scale
- MeshCombiner now handles creation and storing of ResultSceneObject
======================
Version 2.11.8
- Fixed bug with BuildSceneObject so it sets the targetRenderer in the MB2_MeshCombiner
- Enforces expected structure of CombinedMesh scene object
- Warning when using Unity's texture packer
- better interface for AddDeleteGameObjectsByIDs
======================
Version 2.11.7
- Fixed bug with generating UV2 for multi mesh baker
======================
Version 2.11.6
- Fixed bug where meshes could not be combined if the original meshes had been deleted from the scene
- Added warning if skinned mesh has been optimized.
======================
Version 2.11.5
- Fixed bug where combining skinned meshes did not work correctly
- Fixed bug with validation which required resultMaterial to be set when doing multi material
======================
Version 2.11.4
- Improved update so developer has control over which channels are updated.
======================
Version 2.11.3
- Fixed problem copying normal maps to atlases.
======================
Version 2.11.2
- Better calculation of ideal atlas size.
======================
Version 2.11.1
- Fixes error displaying suggested treatment for overlapping submeshes
======================
Version 2.11
- Removed/fixed lines of code that generated warnings
- Add feature that suggests what can be done if meshes don't bake
- If only one texture in an atlas then original textures are re-used
- Refactored much of the texture combining code
======================
Version 2.10
- Changed the internal representation to store instanceIDs instead of GameObjects
this makes it possible to remove destroyed objects as long as the ID instance ID is remembered.
- Added a flag to make validation optional.
- Improved UpdateApproximateBounds and added two scripts that can be do this
- Improved the logging class
- Fixes errors when switching the output after a bake
- Added a version field so dependent projects know the version
======================
Version 2.9.1
Fixes a minor issue where a warning is displayed when skinned meshes
contain no meshes.
======================
Version 2.9
Moved all UnityEditor class usage to classes in the Editor folder
To do this an interface MB2_EditorMethodsInterface and class MB2_EditorMethods were created.
Created new Logging class for better debug tracing
There were a number of changes to the API
MB2_MeshCombiner.Apply takes a delegate function for Generating UV2. This should be null when called at runtime and set to Unwrapping.GenerateUV2 when called from the editor.
These methods require an instance of MB2_EditorMethods when called from the editor. The parameter should be null or ommitted when called at runtime.
doCombinedValidate
CreateAndSaveAtlases
These methods were moved to MB2_EditorMethods
SaveMeshsToAssetDatabase
RebuildPrefab
======================
Version 2.8.3
Fixed bug where can only create one result material when creating multiple result materials
Fixed bug when baking all bakers in scene if one has no objects
Cleaned up error message when have not created texture bake results
======================
Version 2.8.2
Added Mesh Baker texture packer
Added button to auto generate source to combined material mappings from objects to combine
Changed texture format messages from warnings to info messages
Fixed null pointer exception when baking assets in place
cleaned up code in TextureCombiner
Added Show/Hide to the API which just updates triangles

Some files were not shown because too many files have changed in this diff Show More