Net.Like.Xue.Tokyo/Assets/Plugins/MeshCombineStudio/Scripts/Mesh/RemoveGeometryBelowTerrain.cs

276 lines
8.9 KiB
C#

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<Transform> terrains = new List<Transform>();
public List<Transform> meshTerrains = new List<Transform>();
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<MeshFilter>(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<int> newTriangles = new List<int>();
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<Terrain>();
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<MeshRenderer>();
MeshFilter mf = meshTerrains[i].GetComponent<MeshFilter>();
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<Terrain> terrainList = new List<Terrain>();
List<Mesh> meshList = new List<Mesh>();
List<Bounds> terrainBoundsList = new List<Bounds>();
List<Bounds> meshBoundsList = new List<Bounds>();
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<int> 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;
}
}
}
}
}
}
}