using System.Collections; using System.Collections.Generic; using UnityEngine; // This feature will be added in the next update namespace MeshCombineStudio { public class RemoveGeometryBelowTerrain : MonoBehaviour { int totalTriangles; int removeTriangles; int skippedObjects; public List terrains = new List(); public List meshTerrains = new List(); public Bounds[] terrainBounds, meshBounds; Terrain[] terrainComponents; Terrain[] terrainArray; Bounds[] terrainBoundsArray; //, meshBoundsArray; MeshRenderer[] mrs; Mesh[] meshTerrainComponents; Mesh[] meshArray; public bool runOnStart; private void Start() { if (runOnStart) { Remove(gameObject); } } public void Remove(GameObject go) { MeshFilter[] mfs = go.GetComponentsInChildren(true); totalTriangles = 0; removeTriangles = 0; skippedObjects = 0; for (int i = 0; i < mfs.Length; i++) { RemoveMesh(mfs[i].transform, mfs[i].mesh); } Debug.Log("Removeable " + removeTriangles + " total " + totalTriangles + " improvement " + (((float)removeTriangles / totalTriangles) * 100).ToString("F2")); Debug.Log("Skipped Objects " + skippedObjects); } public void RemoveMesh(Transform t, Mesh mesh) { if (mesh == null) return; if (!(IsMeshUnderTerrain(t, mesh))) { ++skippedObjects; return; } Vector3[] vertices = mesh.vertices; List newTriangles = new List(); for (int i = 0; i < mesh.subMeshCount; i++) { newTriangles.AddRange(mesh.GetTriangles(i)); int length = newTriangles.Count; RemoveTriangles(t, newTriangles, vertices); if (newTriangles.Count < length) mesh.SetTriangles(newTriangles.ToArray(), i); } } public bool IsMeshUnderTerrain(Transform t, Mesh mesh) { Bounds bounds = mesh.bounds; bounds.center += t.position; Vector3 min = bounds.min; Vector3 max = bounds.max; //Vector3 center = bounds.center; Vector2 delta = new Vector2(max.x - min.x, max.z - min.z); for (float z = 0; z < 1; z += 0.125f) { for (float x = 0; x < 1; x += 0.125f) { Vector3 p = new Vector3(min.x + (x * delta.x), min.y, min.z + (z * delta.y)); float height = 0;// terrainColliderCam.GetHeight(p); if (p.y < height) return true; } } return false; } public void GetTerrainComponents() { terrainComponents = new Terrain[terrains.Count]; for (int i = 0; i < terrains.Count; i++) { Terrain terrain = terrains[i].GetComponent(); terrainComponents[i] = terrain; } } public void GetMeshRenderersAndComponents() { mrs = new MeshRenderer[meshTerrains.Count]; meshTerrainComponents = new Mesh[meshTerrains.Count]; for (int i = 0; i < meshTerrains.Count; i++) { mrs[i] = meshTerrains[i].GetComponent(); MeshFilter mf = meshTerrains[i].GetComponent(); meshTerrainComponents[i] = mf.sharedMesh; } } public void CreateTerrainBounds() { terrainBounds = new Bounds[terrainComponents.Length]; for (int i = 0; i < terrainBounds.Length; i++) { terrainBounds[i] = new Bounds(); terrainBounds[i].min = terrains[i].position; terrainBounds[i].max = terrainBounds[i].min + terrainComponents[i].terrainData.size; } meshBounds = new Bounds[meshTerrains.Count]; for (int i = 0; i < meshTerrains.Count; i++) { meshBounds[i] = mrs[i].bounds; } } public void MakeIntersectLists(Bounds bounds) { List terrainList = new List(); List meshList = new List(); List terrainBoundsList = new List(); List meshBoundsList = new List(); Vector3[] pos = new Vector3[8]; Vector3 size = bounds.size; pos[0] = bounds.min; pos[1] = pos[0] + new Vector3(size.x, 0, 0); pos[2] = pos[0] + new Vector3(0, 0, size.z); pos[3] = pos[0] + new Vector3(size.x, 0, size.z); pos[4] = pos[0] + new Vector3(0, size.y, 0); pos[5] = pos[0] + new Vector3(size.x, size.y, 0); pos[6] = pos[0] + new Vector3(0, size.y, size.z); pos[7] = pos[0] + size; for (int i = 0; i < 8; i++) { int index = InterectTerrain(pos[i]); if (index != -1) { terrainList.Add(terrainArray[index]); terrainBoundsList.Add(terrainBounds[index]); } index = InterectMesh(pos[i]); if (index != -1) { meshList.Add(meshArray[index]); meshBoundsList.Add(meshBounds[index]); } } terrainArray = terrainList.ToArray(); meshArray = meshList.ToArray(); terrainBoundsArray = terrainBoundsList.ToArray(); // meshBoundsArray = meshBoundsList.ToArray(); } public int InterectTerrain(Vector3 pos) { for (int i = 0; i < terrainBounds.Length; i++) { if (terrainBounds[i].Contains(pos)) return i; } return -1; } public int InterectMesh(Vector3 pos) { for (int i = 0; i < meshBounds.Length; i++) { if (meshBounds[i].Contains(pos)) return i; } return -1; } // Ray ray = new Ray(Vector3.zero, Vector3.down); public float GetTerrainHeight(Vector3 pos) { int index = -1; for (int i = 0; i < terrainArray.Length; i++) { if (terrainBoundsArray[i].Contains(pos)) { index = i; break; } } if (index != -1) { return terrainArray[index].SampleHeight(pos); } return Mathf.Infinity; } public void RemoveTriangles(Transform t, List newTriangles, Vector3[] vertices) { bool[] verticeIsBelow = new bool[vertices.Length]; Vector3 pos = Vector3.zero; float height = 0; for (int j = 0; j < newTriangles.Count; j += 3) { ++totalTriangles; int verticeIndex = newTriangles[j]; bool isBelow = verticeIsBelow[verticeIndex]; if (!isBelow) { pos = t.TransformPoint(vertices[verticeIndex]); height = GetTerrainHeight(pos); isBelow = pos.y < height; } if (isBelow) { verticeIsBelow[verticeIndex] = true; verticeIndex = newTriangles[j + 1]; isBelow = verticeIsBelow[verticeIndex]; if (!isBelow) { pos = t.TransformPoint(vertices[verticeIndex]); height = GetTerrainHeight(pos); isBelow = pos.y < height; } if (isBelow) { verticeIsBelow[verticeIndex] = true; verticeIndex = newTriangles[j + 2]; isBelow = verticeIsBelow[verticeIndex]; if (!isBelow) { pos = t.TransformPoint(vertices[verticeIndex]); height = GetTerrainHeight(pos); isBelow = pos.y < height; } if (isBelow) { verticeIsBelow[verticeIndex] = true; ++removeTriangles; newTriangles.RemoveAt(j + 2); newTriangles.RemoveAt(j + 1); newTriangles.RemoveAt(j); if (j + 3 < newTriangles.Count) j -= 3; } } } } } } }