/**************************************** Simple Mesh Combine Copyright Unluck Software www.chemicalbliss.com *****************************************/ //Add script to the parent gameObject, then click combine using UnityEngine; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif [AddComponentMenu("Simple Mesh Combine")] public class SimpleMeshCombine : MonoBehaviour { public GameObject[] combinedGameOjects; //Stores gameObjects that has been merged, mesh renderer disabled public GameObject combined; //Stores the combined mesh gameObject public string meshName = "Combined_Meshes"; //Asset name when saving as prefab public bool _canGenerateLightmapUV; public int vCount; public bool generateLightmapUV; public float lightmapScale = 1f; public GameObject copyTarget; public bool destroyOldColliders; public bool keepStructure = true; public Mesh autoOverwrite; public bool setStatic = true; public void EnableRenderers(bool e) { for (int i = 0; i < combinedGameOjects.Length; i++) { if (combinedGameOjects[i] == null) break; Renderer renderer = combinedGameOjects[i].GetComponent(); if (renderer != null) renderer.enabled = e; } } //Returns a meshFilter[] list of all renderer enabled meshfilters(so that it does not merge disabled meshes, useful when there are invisible box colliders) public MeshFilter[] FindEnabledMeshes() { MeshFilter[] renderers = null; int count = 0; renderers = transform.GetComponentsInChildren(); //count all the enabled meshrenderers in children for (int i = 0; i < renderers.Length; i++) { if ((renderers[i].GetComponent() != null) && renderers[i].GetComponent().enabled) count++; } MeshFilter[] meshfilters = new MeshFilter[count];//creates a new array with the correct length count = 0; //adds all enabled meshes to the array for (int ii = 0; ii < renderers.Length; ii++) { if ((renderers[ii].GetComponent() != null) && renderers[ii].GetComponent().enabled) { meshfilters[count] = renderers[ii]; count++; } } return meshfilters; } public void CombineMeshes() { GameObject combo = new GameObject(); combo.name = "_Combined Mesh [" + name + "]"; combo.gameObject.AddComponent(); combo.gameObject.AddComponent(); MeshFilter[] meshFilters = null; meshFilters = FindEnabledMeshes(); ArrayList materials = new ArrayList(); ArrayList combineInstanceArrays = new ArrayList(); combinedGameOjects = new GameObject[meshFilters.Length]; for (int i = 0; i < meshFilters.Length; i++) { combinedGameOjects[i] = meshFilters[i].gameObject; MeshRenderer meshRenderer = meshFilters[i].GetComponent(); meshFilters[i].transform.gameObject.GetComponent().enabled = false; if (meshFilters[i].sharedMesh == null) { #if UNITY_EDITOR Debug.LogWarning("SimpleMeshCombine : " + meshFilters[i].gameObject + " [Mesh Filter] has no [Mesh], mesh will not be included in combine.."); #endif break; } for (int o = 0; o < meshFilters[i].sharedMesh.subMeshCount; o++) { if (meshRenderer == null) { #if UNITY_EDITOR Debug.LogWarning("SimpleMeshCombine : " + meshFilters[i].gameObject + "has a [Mesh Filter] but no [Mesh Renderer], mesh will not be included in combine."); #endif break; } if (o < meshRenderer.sharedMaterials.Length && o < meshFilters[i].sharedMesh.subMeshCount) { int materialArrayIndex = Contains(materials, meshRenderer.sharedMaterials[o]); if (materialArrayIndex == -1) { materials.Add(meshRenderer.sharedMaterials[o]); materialArrayIndex = materials.Count - 1; } combineInstanceArrays.Add(new ArrayList()); CombineInstance combineInstance = new CombineInstance(); combineInstance.transform = meshRenderer.transform.localToWorldMatrix; //Fix for Unity 2017 Bug #if UNITY_2017 if (meshFilters[i].sharedMesh.subMeshCount > 1) combineInstance.mesh = SubMeshFix.GetSubmesh(meshFilters[i].sharedMesh,o); else { combineInstance.mesh = meshFilters[i].sharedMesh; } #else combineInstance.mesh = meshFilters[i].sharedMesh; combineInstance.subMeshIndex = o; #endif (combineInstanceArrays[materialArrayIndex] as ArrayList).Add(combineInstance); } #if UNITY_EDITOR else { Debug.LogWarning("Simple Mesh Combine: GameObject [ " + meshRenderer.gameObject.name + " ] is missing a material (Mesh or sub-mesh ignored from combine)"); } #endif } #if UNITY_EDITOR EditorUtility.DisplayProgressBar("Combining", "", (float)i); #endif } Mesh[] meshes = new Mesh[materials.Count]; CombineInstance[] combineInstances = new CombineInstance[materials.Count]; for (int m = 0; m < materials.Count; m++) { CombineInstance[] combineInstanceArray = (combineInstanceArrays[m] as ArrayList).ToArray(typeof(CombineInstance)) as CombineInstance[]; meshes[m] = new Mesh(); meshes[m].CombineMeshes(combineInstanceArray, true, true); combineInstances[m] = new CombineInstance(); combineInstances[m].mesh = meshes[m]; combineInstances[m].subMeshIndex = 0; } Mesh ms = combo.GetComponent().sharedMesh = new Mesh(); ms.Clear(); ms.CombineMeshes(combineInstances, false, false); combo.GetComponent().sharedMesh = ms; foreach (Mesh mesh in meshes) { mesh.Clear(); DestroyImmediate(mesh); } MeshRenderer meshRendererCombine = combo.GetComponent().GetComponent(); if (meshRendererCombine == null) meshRendererCombine = gameObject.AddComponent(); Material[] materialsArray = materials.ToArray(typeof(Material)) as Material[]; meshRendererCombine.materials = materialsArray; combined = combo.gameObject; EnableRenderers(false); combo.transform.parent = transform; #if UNITY_EDITOR if (generateLightmapUV) { Unwrapping.GenerateSecondaryUVSet(combo.GetComponent().sharedMesh); SerializedObject so = new SerializedObject (combo.GetComponent()); so.FindProperty("m_ScaleInLightmap").floatValue = lightmapScale; so.ApplyModifiedProperties(); } #endif combo.GetComponent().sharedMesh.RecalculateBounds(); vCount = combo.GetComponent().sharedMesh.vertexCount; if (vCount > 65536) { Debug.LogWarning("Vertex Count: " + vCount + "- Vertex Count too high, please divide mesh combine into more groups. Max 65536 for each mesh"); _canGenerateLightmapUV = false; } else { _canGenerateLightmapUV = true; } if (setStatic) combined.isStatic = true; #if UNITY_EDITOR EditorUtility.ClearProgressBar(); #endif } public int Contains(ArrayList l, Material n) { for (int i = 0; i < l.Count; i++) { if ((l[i] as Material) == n) { return i; } } return -1; } }