public static bool combineMeshes(GameObject parent, Vector3 parentPosition, Quaternion parentRotation) { //bool showCompileReady = true; //double timeStart = EditorApplication.timeSinceStartup; List <CustomMesh> meshes = new List <CustomMesh> (); List <MeshesByMaterial> meshesByMaterial = new List <MeshesByMaterial> (); int numChildren = parent.transform.childCount; int childIdx = 0; List <Material> materials = new List <Material> (); Bounds gridBounds = new Bounds(); bool foundBounds = false; //Build custom meshes foreach (Transform child in parent.transform) { // Get bounds Renderer[] renderers = child.GetComponentsInChildren <Renderer> (); List <Renderer> rds = new List <Renderer> (renderers); if (rds.Count == 0) { continue; } for (int i = 0; i < rds.Count; i++) { Renderer r = rds [i]; Material material = r.sharedMaterial; if (material) { if (!materials.Contains(material)) { materials.Add(material); } } if (!foundBounds) { foundBounds = true; gridBounds = new Bounds(r.bounds.center, r.bounds.size); } else { gridBounds.Encapsulate(r.bounds); } } MeshFilter[] ccmfs = child.GetComponentsInChildren <MeshFilter> (); List <MeshFilter> mfs = new List <MeshFilter> (ccmfs); for (int i = 0; i < mfs.Count; i++) { MeshFilter mf = mfs [i]; Renderer r = mf.gameObject.GetComponent <Renderer> (); if (!r) { continue; } Material material = r.sharedMaterial; if (!material || !materials.Contains(material)) { continue; } int materialIndex = materials.IndexOf(material); bool cancel = false; Mesh mesh = mf.sharedMesh; string name = child.name; if (mesh == null) { continue; } float percent = ((float)childIdx) / ((float)numChildren); cancel = EditorUtility.DisplayCancelableProgressBar("Creating custom meshes...", "(" + childIdx + "/" + numChildren + ") " + name, percent); if (cancel) { return(true); } // Keeps this mesh but compares to others. No subdivision is performed. bool keep = (child.tag == "keep"); // Keeps this mesh without comparing to others. No subdivision is performed. bool noCompare = (child.tag == "nocompare"); CustomMesh cm = buildTriangles(mesh, name, mf.transform, keep, noCompare, materialIndex); meshes.Add(cm); if (meshesByMaterial.Count <= materialIndex) { MeshesByMaterial mbm = new MeshesByMaterial(); meshesByMaterial.Add(mbm); } meshesByMaterial [materialIndex].addMesh(cm); } childIdx++; } // Create mesh grid int gridSize = (int)Mathf.Ceil(gridBounds.size.x); if (Mathf.Ceil(gridBounds.size.y) > gridSize) { gridSize = (int)Mathf.Ceil(gridBounds.size.y); } if (Mathf.Ceil(gridBounds.size.z) > gridSize) { gridSize = (int)Mathf.Ceil(gridBounds.size.z); } MeshGrid meshGrid = new MeshGrid(gridSize, gridBounds.center); foreach (CustomMesh m in meshes) { if (!m.noCompare) { meshGrid.addMesh(m); } } int triangleCount = 0; int vertexCount = 0; // Remove obsolete triangles for (int i = 0; i < meshes.Count; i++) { CustomMesh m = meshes [i]; if (!m.noCompare) { float percent = ((float)i) / ((float)meshes.Count); string name = m.name + ""; bool cancel = false; cancel = EditorUtility.DisplayCancelableProgressBar("Checking triangles...", " (" + i + "/" + meshes.Count + ") " + name, percent); if (cancel) { return(true); } for (int j = 0; j < m.gridItems.Count; j++) { m.gridItems [j].checkMesh(m); } } int tCount = 0; int vCount = 0; m.getVertexAndTriangleCount(ref vCount, ref tCount); //Debug.Log ("Mesh " + m.name + " has " + tCount / 3 + " triangles."); triangleCount += tCount; vertexCount += vCount; EditorApplication.Step(); } buildQuadsFromTriangles(meshes); triangleCount = 0; vertexCount = 0; for (int i = 0; i < meshes.Count; i++) { CustomMesh m = meshes [i]; if (!m.noCompare) { float percent = ((float)i) / ((float)meshes.Count); string name = m.name + ""; bool cancel = false; cancel = EditorUtility.DisplayCancelableProgressBar("Checking quads...", " (" + i + "/" + meshes.Count + ") " + name, percent); if (cancel) { return(true); } for (int j = 0; j < m.gridItems.Count; j++) { m.gridItems [j].checkMesh(m); } } int tCount = 0; int vCount = 0; m.getVertexAndTriangleCount(ref vCount, ref tCount); //Debug.Log ("Mesh " + m.name + " has " + tCount / 3 + " triangles."); triangleCount += tCount; vertexCount += vCount; EditorApplication.Step(); } EditorUtility.ClearProgressBar(); int currentMaterial = 0; foreach (MeshesByMaterial mbm in meshesByMaterial) { triangleCount = 0; vertexCount = 0; for (int i = 0; i < mbm.meshes.Count; i++) { int vCount = 0; int tCount = 0; mbm.meshes [i].getVertexAndTriangleCount(ref vCount, ref tCount); triangleCount += tCount; vertexCount += vCount; } if (vertexCount == 0 || triangleCount == 0) { continue; } // Combine all quads/triangles to one big mesh GameObject go = new GameObject("_Combined_" + parent.name + "_material_" + materials [currentMaterial].name); go.transform.position = parentPosition; go.transform.rotation = parentRotation; go.transform.localScale = Vector3.one; if (parent.transform && parent.transform.parent && parent.transform.parent.gameObject) { go.transform.parent = parent.transform.parent; } GameObjectUtility.SetStaticEditorFlags(go, StaticEditorFlags.LightmapStatic); MeshRenderer renderer = go.AddComponent <MeshRenderer> (); if (materials [currentMaterial] != null) { renderer.material = materials [currentMaterial]; } currentMaterial++; MeshFilter newFilter = go.AddComponent <MeshFilter> (); Mesh newMesh = new Mesh(); Vector3[] newVertices = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[newVertices.Length]; Vector3[] newNormals = new Vector3[newVertices.Length]; int[] newTriangles = new int[triangleCount]; int triangleIndex = 0; int vertexIndex = 0; for (int i = 0; i < mbm.meshes.Count; i++) { mbm.meshes [i].getTrianglesAndVertices(ref newTriangles, ref newVertices, ref newUV, ref newNormals, ref triangleIndex, ref vertexIndex); } newMesh.vertices = newVertices; newMesh.normals = newNormals; newMesh.uv = newUV; newMesh.uv2 = newUV; newMesh.triangles = newTriangles; ; newMesh.RecalculateBounds(); newFilter.mesh = newMesh; Unwrapping.GenerateSecondaryUVSet(newFilter.sharedMesh); } //Debug.Log ("Combine meshes finished! Elapsed time: " + (EditorApplication.timeSinceStartup - timeStart)); return(false); }
public static bool combineMeshes (GameObject parent, Vector3 parentPosition, Quaternion parentRotation) { //bool showCompileReady = true; //double timeStart = EditorApplication.timeSinceStartup; List<CustomMesh> meshes = new List<CustomMesh> (); List<MeshesByMaterial> meshesByMaterial = new List<MeshesByMaterial> (); int numChildren = parent.transform.childCount; int childIdx = 0; List<Material> materials = new List<Material> (); Bounds gridBounds = new Bounds (); bool foundBounds = false; //Build custom meshes foreach (Transform child in parent.transform) { // Get bounds Renderer[] renderers = child.GetComponentsInChildren<Renderer> (); List<Renderer> rds = new List<Renderer> (renderers); if (rds.Count == 0) { continue; } for (int i=0; i<rds.Count; i++) { Renderer r = rds [i]; Material material = r.sharedMaterial; if (material) { if (!materials.Contains (material)) { materials.Add (material); } } if (!foundBounds) { foundBounds = true; gridBounds = new Bounds (r.bounds.center, r.bounds.size); } else { gridBounds.Encapsulate (r.bounds); } } MeshFilter[] ccmfs = child.GetComponentsInChildren<MeshFilter> (); List<MeshFilter> mfs = new List<MeshFilter> (ccmfs); for (int i=0; i<mfs.Count; i++) { MeshFilter mf = mfs [i]; Renderer r = mf.gameObject.GetComponent<Renderer> (); if(!r){ continue; } Material material = r.sharedMaterial; if (!material || !materials.Contains (material)) { continue; } int materialIndex = materials.IndexOf (material); bool cancel = false; Mesh mesh = mf.sharedMesh; string name = child.name; if (mesh == null) { continue; } float percent = ((float)childIdx) / ((float)numChildren); cancel = EditorUtility.DisplayCancelableProgressBar ("Creating custom meshes...", "(" + childIdx + "/" + numChildren + ") " + name, percent); if (cancel) { return true; } // Keeps this mesh but compares to others. No subdivision is performed. bool keep = (child.tag == "keep"); // Keeps this mesh without comparing to others. No subdivision is performed. bool noCompare = (child.tag == "nocompare"); CustomMesh cm = buildTriangles (mesh, name, mf.transform, keep, noCompare, materialIndex); meshes.Add (cm); if (meshesByMaterial.Count <= materialIndex) { MeshesByMaterial mbm = new MeshesByMaterial (); meshesByMaterial.Add (mbm); } meshesByMaterial [materialIndex].addMesh (cm); } childIdx ++; } // Create mesh grid int gridSize = (int)Mathf.Ceil (gridBounds.size.x); if (Mathf.Ceil (gridBounds.size.y) > gridSize) { gridSize = (int)Mathf.Ceil (gridBounds.size.y); } if (Mathf.Ceil (gridBounds.size.z) > gridSize) { gridSize = (int)Mathf.Ceil (gridBounds.size.z); } MeshGrid meshGrid = new MeshGrid (gridSize, gridBounds.center); foreach (CustomMesh m in meshes) { if (!m.noCompare) { meshGrid.addMesh (m); } } int triangleCount = 0; int vertexCount = 0; // Remove obsolete triangles for (int i=0; i<meshes.Count; i++) { CustomMesh m = meshes [i]; if (!m.noCompare) { float percent = ((float)i) / ((float)meshes.Count); string name = m.name + ""; bool cancel = false; cancel = EditorUtility.DisplayCancelableProgressBar ("Checking triangles...", " (" + i + "/" + meshes.Count + ") " + name, percent); if (cancel) { return true; } for (int j=0; j<m.gridItems.Count; j++) { m.gridItems [j].checkMesh (m); } } int tCount = 0; int vCount = 0; m.getVertexAndTriangleCount (ref vCount, ref tCount); //Debug.Log ("Mesh " + m.name + " has " + tCount / 3 + " triangles."); triangleCount += tCount; vertexCount += vCount; EditorApplication.Step (); } buildQuadsFromTriangles (meshes); triangleCount = 0; vertexCount = 0; for (int i=0; i<meshes.Count; i++) { CustomMesh m = meshes [i]; if (!m.noCompare) { float percent = ((float)i) / ((float)meshes.Count); string name = m.name + ""; bool cancel = false; cancel = EditorUtility.DisplayCancelableProgressBar ("Checking quads...", " (" + i + "/" + meshes.Count + ") " + name, percent); if (cancel) { return true; } for (int j=0; j<m.gridItems.Count; j++) { m.gridItems [j].checkMesh (m); } } int tCount = 0; int vCount = 0; m.getVertexAndTriangleCount (ref vCount, ref tCount); //Debug.Log ("Mesh " + m.name + " has " + tCount / 3 + " triangles."); triangleCount += tCount; vertexCount += vCount; EditorApplication.Step (); } EditorUtility.ClearProgressBar (); int currentMaterial = 0; foreach (MeshesByMaterial mbm in meshesByMaterial) { triangleCount = 0; vertexCount = 0; for (int i=0; i < mbm.meshes.Count; i++) { int vCount = 0; int tCount = 0; mbm.meshes [i].getVertexAndTriangleCount (ref vCount, ref tCount); triangleCount += tCount; vertexCount += vCount; } if(vertexCount == 0 || triangleCount == 0){ continue; } // Combine all quads/triangles to one big mesh GameObject go = new GameObject ("_Combined_" + parent.name + "_material_" + materials [currentMaterial].name); go.transform.position = parentPosition; go.transform.rotation = parentRotation; go.transform.localScale = Vector3.one; if (parent.transform && parent.transform.parent && parent.transform.parent.gameObject) { go.transform.parent = parent.transform.parent; } GameObjectUtility.SetStaticEditorFlags (go, StaticEditorFlags.LightmapStatic); MeshRenderer renderer = go.AddComponent<MeshRenderer> (); if (materials [currentMaterial] != null) { renderer.material = materials [currentMaterial]; } currentMaterial ++; MeshFilter newFilter = go.AddComponent<MeshFilter> (); Mesh newMesh = new Mesh (); Vector3[] newVertices = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[newVertices.Length]; Vector3[] newNormals = new Vector3[newVertices.Length]; int[] newTriangles = new int[triangleCount]; int triangleIndex = 0; int vertexIndex = 0; for (int i=0; i<mbm.meshes.Count; i++) { mbm.meshes [i].getTrianglesAndVertices (ref newTriangles, ref newVertices, ref newUV, ref newNormals, ref triangleIndex, ref vertexIndex); } newMesh.vertices = newVertices; newMesh.normals = newNormals; newMesh.uv = newUV; newMesh.uv2 = newUV; newMesh.triangles = newTriangles; newMesh.Optimize (); newMesh.RecalculateBounds (); newFilter.mesh = newMesh; Unwrapping.GenerateSecondaryUVSet (newFilter.sharedMesh); } //Debug.Log ("Combine meshes finished! Elapsed time: " + (EditorApplication.timeSinceStartup - timeStart)); return false; }