-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
using UnityEngine; | ||
using UnityEditor; | ||
using System.Collections.Generic; | ||
using UnityEngine.Rendering; | ||
|
||
public class MeshCombineWizard : ScriptableWizard | ||
{ | ||
public GameObject combineParent; | ||
public bool is32bit = true; | ||
|
||
[MenuItem("E.S. Tools/Mesh Combine Wizard")] | ||
static void CreateWizard() | ||
{ | ||
var wizard = DisplayWizard<MeshCombineWizard>("Mesh Combine Wizard"); | ||
|
||
// If there is selection, and the selection of one Scene object, auto-assign it | ||
var selectionObjects = Selection.objects; | ||
if (selectionObjects != null && selectionObjects.Length == 1) | ||
{ | ||
var firstSelection = selectionObjects[0] as GameObject; | ||
if (firstSelection != null) | ||
{ | ||
wizard.combineParent = firstSelection; | ||
} | ||
} | ||
} | ||
|
||
void OnWizardCreate() | ||
{ | ||
// Verify there is existing object root, ptherwise bail. | ||
if (combineParent == null) | ||
{ | ||
Debug.LogError("Mesh Combine Wizard: Parent of objects to combne not assigned. Operation cancelled."); | ||
return; | ||
} | ||
|
||
// Remember the original position of the object. | ||
// For the operation to work, the position must be temporarily set to (0,0,0). | ||
Vector3 originalPosition = combineParent.transform.position; | ||
combineParent.transform.position = Vector3.zero; | ||
|
||
// Locals | ||
Dictionary<Material, List<MeshFilter>> materialToMeshFilterList = new Dictionary<Material, List<MeshFilter>>(); | ||
List<GameObject> combinedObjects = new List<GameObject>(); | ||
|
||
MeshFilter[] meshFilters = combineParent.GetComponentsInChildren<MeshFilter>(); | ||
|
||
// Go through all mesh filters and establish the mapping between the materials and all mesh filters using it. | ||
foreach (var meshFilter in meshFilters) | ||
{ | ||
var meshRenderer = meshFilter.GetComponent<MeshRenderer>(); | ||
if (meshRenderer == null) | ||
{ | ||
Debug.LogWarning("The Mesh Filter on object " + meshFilter.name + " has no Mesh Renderer component attached. Skipping."); | ||
continue; | ||
} | ||
|
||
var materials = meshRenderer.sharedMaterials; | ||
if (materials == null) | ||
{ | ||
Debug.LogWarning("The Mesh Renderer on object " + meshFilter.name + " has no material assigned. Skipping."); | ||
continue; | ||
} | ||
|
||
// If there are multiple materials on a single mesh, cancel. | ||
if (materials.Length > 1) | ||
{ | ||
// Rollback: return the object to original position | ||
combineParent.transform.position = originalPosition; | ||
Debug.LogError("Objects with multiple materials on the same mesh are not supported. Create multiple meshes from this object's sub-meshes in an external 3D tool and assign separate materials to each. Operation cancelled."); | ||
return; | ||
} | ||
var material = materials[0]; | ||
|
||
// Add material to mesh filter mapping to dictionary | ||
if (materialToMeshFilterList.ContainsKey(material)) materialToMeshFilterList[material].Add(meshFilter); | ||
else materialToMeshFilterList.Add(material, new List<MeshFilter>() { meshFilter }); | ||
} | ||
|
||
// For each material, create a new merged object, in the scene and in the assets folder. | ||
foreach (var entry in materialToMeshFilterList) | ||
{ | ||
List<MeshFilter> meshesWithSameMaterial = entry.Value; | ||
// Create a convenient material name | ||
string materialName = entry.Key.ToString().Split(' ')[0]; | ||
|
||
CombineInstance[] combine = new CombineInstance[meshesWithSameMaterial.Count]; | ||
for (int i = 0; i < meshesWithSameMaterial.Count; i++) | ||
{ | ||
combine[i].mesh = meshesWithSameMaterial[i].sharedMesh; | ||
combine[i].transform = meshesWithSameMaterial[i].transform.localToWorldMatrix; | ||
} | ||
|
||
// Create a new mesh using the combined properties | ||
var format = is32bit ? IndexFormat.UInt32 : IndexFormat.UInt16; | ||
Mesh combinedMesh = new Mesh { indexFormat = format }; | ||
combinedMesh.CombineMeshes(combine); | ||
|
||
// Create asset | ||
materialName += "_" + combinedMesh.GetInstanceID(); | ||
AssetDatabase.CreateAsset(combinedMesh, "Assets/CombinedMeshes_" + materialName + ".asset"); | ||
|
||
// Create game object | ||
string goName = (materialToMeshFilterList.Count > 1) ? "CombinedMeshes_" + materialName : "CombinedMeshes_" + combineParent.name; | ||
GameObject combinedObject = new GameObject(goName); | ||
var filter = combinedObject.AddComponent<MeshFilter>(); | ||
filter.sharedMesh = combinedMesh; | ||
var renderer = combinedObject.AddComponent<MeshRenderer>(); | ||
renderer.sharedMaterial = entry.Key; | ||
combinedObjects.Add(combinedObject); | ||
} | ||
|
||
// If there were more than one material, and thus multiple GOs created, parent them and work with result | ||
GameObject resultGO = null; | ||
if (combinedObjects.Count > 1) | ||
{ | ||
resultGO = new GameObject("CombinedMeshes_" + combineParent.name); | ||
foreach (var combinedObject in combinedObjects) combinedObject.transform.parent = resultGO.transform; | ||
} | ||
else | ||
{ | ||
resultGO = combinedObjects[0]; | ||
} | ||
|
||
// Create prefab | ||
Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/" + resultGO.name + ".prefab"); | ||
PrefabUtility.ReplacePrefab(resultGO, prefab, ReplacePrefabOptions.ConnectToPrefab); | ||
|
||
// Disable the original and return both to original positions | ||
combineParent.SetActive(false); | ||
combineParent.transform.position = originalPosition; | ||
resultGO.transform.position = originalPosition; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.