Files
SimUL/Packages/Floorplan-2.0/Scripts/MeshCombiner.cs
T
2023-10-06 10:09:30 +03:00

298 lines
12 KiB
C#

using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using UnityEditor.UI;
public class MeshCombiner : MonoBehaviour
{
GameObject wallMesh;
GameObject floorMesh;
public void Awake()
{
}
private void Start()
{
wallMesh = new GameObject("WallMesh", typeof(MeshFilter), typeof(Renderer));
floorMesh = new GameObject("FloorMesh", typeof(MeshFilter), typeof(Renderer));
print(transform.childCount);
for (int i = transform.childCount - 1; i >= 0; --i)
{
Transform child = transform.GetChild(i);
if (child.name == "Floor")
child.SetParent(floorMesh.transform, true);
else if (child.name == "Walls")
child.SetParent(wallMesh.transform, true);
}
wallMesh.transform.parent = transform;
floorMesh.transform.parent = transform;
CombineWalls();
CombineFloor();
ClearChildren(floorMesh.transform);
ClearChildren(wallMesh.transform);
SplitMesh(floorMesh.GetComponent<MeshFilter>());
SplitMesh(wallMesh.GetComponent<MeshFilter>());
for (int i = 0; i < floorMesh.transform.childCount; i++)
{
Simplify(floorMesh.transform.GetChild(i).GetComponent<MeshFilter>());
}
for (int i = 0; i < wallMesh.transform.childCount; i++)
{
Simplify(wallMesh.transform.GetChild(i).GetComponent<MeshFilter>());
}
}
void ClearChildren(Transform t)
{
for(int i=0; i<t.childCount; i++)
{
Destroy(t.GetChild(i).gameObject);
}
}
private void Simplify(MeshFilter mf)
{
if (mf != null)
{
mf.mesh.Weld(0.00000328f, 1f);
mf.mesh.Simplify();
}
}
void SplitMesh(MeshFilter mf)
{
for (int i = 0; i < mf.mesh.subMeshCount; i++)
{
GameObject gO = new GameObject();
gO.name = mf.gameObject.name + " submesh " + (i+1).ToString();
gO.transform.parent = mf.gameObject.transform;
MeshFilter filter = gO.AddComponent<MeshFilter>();
filter.mesh=mf.mesh.GetSubmesh(i);
Renderer r = gO.AddComponent<MeshRenderer>();
r.material = mf.gameObject.GetComponent<Renderer>().materials[i];
MeshCollider c = gO.AddComponent<MeshCollider>();
c.sharedMesh = filter.mesh;
}
Destroy(mf.gameObject.GetComponent<Renderer>());
Destroy(mf.gameObject.GetComponent<MeshCollider>());
}
private void CombineWalls()
{
Vector3 basePosition = transform.position;
Quaternion baseRotation = transform.rotation;
transform.position = Vector3.zero;
transform.rotation = Quaternion.identity;
ArrayList materials = new ArrayList();
ArrayList combineInstanceArrays = new ArrayList();
MeshFilter[] meshFilters = wallMesh.GetComponentsInChildren<MeshFilter>();
//Linq solution to make sure we don't combine any of the doors(a door is easily identifiable by it's rigidbody component, so we look for that).
meshFilters = meshFilters.Where((source, index) => !(source.transform.name == "FloorMesh" || source.transform.name == "WallMesh" || source.transform.GetComponent<Rigidbody>() || source.transform.GetComponentInParent<Rigidbody>())).ToArray();
foreach (MeshFilter meshFilter in meshFilters)
{
MeshRenderer meshRenderer = meshFilter.GetComponent<MeshRenderer>();
if (!meshRenderer ||
!meshFilter.sharedMesh ||
meshRenderer.sharedMaterials.Length != meshFilter.sharedMesh.subMeshCount)
{
print(meshFilter.gameObject.name);
continue;
}
for (int s = 0; s < meshFilter.sharedMesh.subMeshCount; s++)
{
if (meshRenderer.sharedMaterials[s]){
int materialArrayIndex = Contains(materials, meshRenderer.sharedMaterials[s].name);
if (materialArrayIndex == -1)
{
materials.Add(meshRenderer.sharedMaterials[s]);
materialArrayIndex = materials.Count - 1;
}
combineInstanceArrays.Add(new ArrayList());
CombineInstance combineInstance = new CombineInstance();
combineInstance.transform = meshRenderer.transform.localToWorldMatrix;
combineInstance.subMeshIndex = s;
combineInstance.mesh = meshFilter.sharedMesh;
(combineInstanceArrays[materialArrayIndex] as ArrayList).Add(combineInstance);
}
}
}
// Get / Create mesh filter & renderer
MeshFilter meshFilterCombine = wallMesh.GetComponent<MeshFilter>();
if (meshFilterCombine == null)
{
meshFilterCombine = wallMesh.AddComponent<MeshFilter>();
}
MeshRenderer meshRendererCombine = gameObject.GetComponent<MeshRenderer>();
if (meshRendererCombine == null)
{
meshRendererCombine = wallMesh.AddComponent<MeshRenderer>();
}
// Combine by material index into per-material meshes
// also, Create CombineInstance array for next step
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;
}
// Combine into one
meshFilterCombine.sharedMesh = new Mesh();
meshFilterCombine.sharedMesh.CombineMeshes(combineInstances, false, false);
// Destroy other meshes
foreach (Mesh oldMesh in meshes)
{
oldMesh.Clear();
DestroyImmediate(oldMesh);
}
// Assign materials
Material[] materialsArray = materials.ToArray(typeof(Material)) as Material[];
meshRendererCombine.materials = materialsArray;
foreach (MeshFilter meshFilter in meshFilters)
{
if (!meshFilter || meshFilter.transform.GetComponent<Rigidbody>() || meshFilter.transform.GetComponentInParent<Rigidbody>() || meshFilter.transform.GetComponentInChildren<Rigidbody>())
continue;
print(meshFilter.gameObject.transform.parent.name);
DestroyImmediate(meshFilter.gameObject.transform.parent.gameObject);
}
wallMesh.transform.position = basePosition;
wallMesh.transform.rotation = baseRotation;
wallMesh.AddComponent<MeshCollider>().sharedMesh = wallMesh.GetComponent<MeshFilter>().sharedMesh;
}
private void CombineFloor()
{
Vector3 basePosition = transform.position;
Quaternion baseRotation = transform.rotation;
transform.position = Vector3.zero;
transform.rotation = Quaternion.identity;
ArrayList materials = new ArrayList();
ArrayList combineInstanceArrays = new ArrayList();
MeshFilter[] meshFilters = floorMesh.GetComponentsInChildren<MeshFilter>();
//Linq solution to make sure we don't combine any of the doors(a door is easily identifiable by it's rigidbody component, so we look for that).
meshFilters = meshFilters.Where((source, index) => !(source.transform.name=="FloorMesh" || source.transform.name=="WallMesh" || source.transform.GetComponent<Rigidbody>() || source.transform.GetComponentInParent<Rigidbody>())).ToArray();
foreach (MeshFilter meshFilter in meshFilters)
{
MeshRenderer meshRenderer = meshFilter.GetComponent<MeshRenderer>();
if (!meshRenderer ||
!meshFilter.sharedMesh ||
meshRenderer.sharedMaterials.Length != meshFilter.sharedMesh.subMeshCount)
{
continue;
}
for (int s = 0; s < meshFilter.sharedMesh.subMeshCount; s++)
{
if (meshRenderer.sharedMaterials[s])
{
int materialArrayIndex = Contains(materials, meshRenderer.sharedMaterials[s].name);
if (materialArrayIndex == -1)
{
materials.Add(meshRenderer.sharedMaterials[s]);
materialArrayIndex = materials.Count - 1;
}
combineInstanceArrays.Add(new ArrayList());
CombineInstance combineInstance = new CombineInstance();
combineInstance.transform = meshRenderer.transform.localToWorldMatrix;
combineInstance.subMeshIndex = s;
combineInstance.mesh = meshFilter.sharedMesh;
(combineInstanceArrays[materialArrayIndex] as ArrayList).Add(combineInstance);
}
}
}
// Get / Create mesh filter & renderer
MeshFilter meshFilterCombine = floorMesh.GetComponent<MeshFilter>();
if (meshFilterCombine == null)
{
meshFilterCombine = floorMesh.AddComponent<MeshFilter>();
}
MeshRenderer meshRendererCombine = gameObject.GetComponent<MeshRenderer>();
if (meshRendererCombine == null)
{
meshRendererCombine = floorMesh.AddComponent<MeshRenderer>();
}
// Combine by material index into per-material meshes
// also, Create CombineInstance array for next step
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;
}
// Combine into one
meshFilterCombine.sharedMesh = new Mesh();
meshFilterCombine.sharedMesh.CombineMeshes(combineInstances, false, false);
// Destroy other meshes
foreach (Mesh oldMesh in meshes)
{
oldMesh.Clear();
DestroyImmediate(oldMesh);
}
// Assign materials
Material[] materialsArray = materials.ToArray(typeof(Material)) as Material[];
meshRendererCombine.materials = materialsArray;
foreach (MeshFilter meshFilter in meshFilters)
{
if (!meshFilter || meshFilter.transform.GetComponent<Rigidbody>() || meshFilter.transform.GetComponentInParent<Rigidbody>() || meshFilter.transform.GetComponentInChildren<Rigidbody>())
continue;
DestroyImmediate(meshFilter.gameObject.transform.parent.gameObject);
}
floorMesh.transform.position = basePosition;
floorMesh.transform.rotation = baseRotation;
floorMesh.AddComponent<MeshCollider>().sharedMesh = floorMesh.GetComponent<MeshFilter>().sharedMesh;
}
private int Contains(ArrayList searchList, string searchName)
{
for (int i = 0; i < searchList.Count; i++)
{
if (((Material)searchList[i]).name == searchName)
{
return i;
}
}
return -1;
}
}