This commit is contained in:
2025-11-14 18:44:06 +08:00
parent 10156da245
commit 22e867d077
7013 changed files with 2572882 additions and 1804 deletions

View File

@@ -0,0 +1,264 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class CamGeometryCapture : MonoBehaviour
{
public ComputeShader computeDepthToArray;
public Int2 resolution = new Int2(1024, 1024);
// public bool capture;
// public float radius = 0.5f;
public Camera cam;
public Transform t;
public RenderTexture rtCapture;
float[] heights;
Bounds bounds;
float maxSize;
public void Init()
{
if (t != null) return;
t = transform;
cam = GetComponent<Camera>();
cam.aspect = 1;
cam.orthographic = true;
}
void OnDestroy()
{
DisposeRTCapture();
}
//void Update()
//{
// if (capture)
// {
// capture = false;
// Capture(mr.bounds, collisionMask.value, direction, resolution);
// }
//}
void DisposeRenderTexture(ref RenderTexture rt)
{
if (rt == null) return;
rt.Release();
#if UNITY_EDITOR
DestroyImmediate(rt);
#else
Destroy(rt);
#endif
rt = null;
}
public void DisposeRTCapture()
{
cam.targetTexture = null;
DisposeRenderTexture(ref rtCapture);
}
public void RemoveTrianglesBelowSurface(Transform t, MeshCombineJobManager.MeshCombineJob meshCombineJob, MeshCache.SubMeshCache newMeshCache, ref byte[] vertexIsBelow)
{
if (vertexIsBelow == null) vertexIsBelow = new byte[65534];
Vector3 pos = Vector3.zero;
int layerMask = meshCombineJob.meshCombiner.surfaceLayerMask;
// float rayHeight = meshCombineJob.meshCombiner.maxSurfaceHeight;
Vector3[] newVertices = newMeshCache.vertices;
int[] newTriangles = newMeshCache.triangles;
List<MeshObject> meshObjects = meshCombineJob.meshObjectsHolder.meshObjects;
int startIndex = meshCombineJob.startIndex;
int endIndex = meshCombineJob.endIndex;
const byte belowSurface = 1, aboveSurface = 2;
for (int i = startIndex; i < endIndex; i++)
{
MeshObject meshObject = meshObjects[i];
Capture(meshObject.cachedGO.mr.bounds, layerMask, new Vector3(0, -1, 0), new Int2(1024, 1024));
int startTriangleIndex = meshObject.startNewTriangleIndex;
int endTriangleIndex = meshObject.newTriangleCount + startTriangleIndex;
// Debug.Log("startIndex " + startIndex + " triangle " + startTriangleIndex + " - " + endTriangleIndex);
for (int j = startTriangleIndex; j < endTriangleIndex; j += 3)
{
bool isAboveSurface = false;
for (int k = 0; k < 3; k++)
{
int vertexIndex = newTriangles[j + k];
if (vertexIndex == -1) continue;
byte isBelow = vertexIsBelow[vertexIndex];
if (isBelow == 0)
{
pos = t.TransformPoint(newVertices[vertexIndex]);
float height = GetHeight(pos);
isBelow = pos.y < height ? belowSurface : aboveSurface;
vertexIsBelow[vertexIndex] = isBelow;
if (pos.y < height)
{
vertexIsBelow[vertexIndex] = isBelow = belowSurface;
}
else
{
vertexIsBelow[vertexIndex] = isBelow = aboveSurface;
}
}
if (isBelow != belowSurface) { isAboveSurface = true; break; }
}
if (!isAboveSurface)
{
meshCombineJob.trianglesRemoved += 3;
newTriangles[j] = -1;
}
}
}
Array.Clear(vertexIsBelow, 0, newVertices.Length);
}
public void Capture(Bounds bounds, int collisionMask, Vector3 direction, Int2 resolution)
{
if (rtCapture == null || rtCapture.width != resolution.x || rtCapture.height != resolution.y)
{
if (rtCapture != null) DisposeRTCapture();
rtCapture = new RenderTexture(resolution.x, resolution.y, 16, RenderTextureFormat.Depth, RenderTextureReadWrite.Linear);
}
bounds.size *= 1.1f;
this.bounds = bounds;
cam.targetTexture = rtCapture;
cam.cullingMask = collisionMask;
SetCamera(direction);
cam.Render();
int heightsLength = resolution.x * resolution.y;
ComputeBuffer heightBuffer = new ComputeBuffer(heightsLength, 4);
computeDepthToArray.SetTexture(0, "rtDepth", rtCapture);
computeDepthToArray.SetBuffer(0, "heightBuffer", heightBuffer);
computeDepthToArray.SetInt("resolution", resolution.x);
computeDepthToArray.SetFloat("captureHeight", t.position.y);
computeDepthToArray.SetFloat("distance", bounds.size.y + 256);
computeDepthToArray.SetInt("direction", direction.y == 1 ? 1 : -1);
computeDepthToArray.Dispatch(0, Mathf.CeilToInt(resolution.x / 8), Mathf.CeilToInt(resolution.y / 8), 1);
if (heights == null || heights.Length != heightsLength) heights = new float[heightsLength];
heightBuffer.GetData(heights);
// Debug.Log(bounds.size.x + " " + bounds.size.y + " " + bounds.size.z);
heightBuffer.Dispose();
}
//private void OnDrawGizmos()
//{
// Gizmos.color = Color.red;
// Mesh m = mf.sharedMesh;
// Vector3[] vertices = m.vertices;
// // Vector3 startPos = new Vector3(t.position.x, 0, t.position.z) - new Vector3(maxSize / 2, 0, maxSize / 2);
// for (int i = 0; i < vertices.Length; i++)
// {
// Vector3 pos = mf.transform.TransformPoint(vertices[i]);
// pos.y = GetHeight(pos);
// Gizmos.DrawSphere(pos, radius);
// }
//}
public void SetCamera(Vector3 direction)
{
if (direction == new Vector3(0, 1, 0))
{
t.position = bounds.center - new Vector3(0, bounds.extents.y + 256, 0);
}
else if (direction == new Vector3(0, -1, 0))
{
t.position = bounds.center + new Vector3(0, bounds.extents.y + 256, 0);
}
t.forward = direction;
maxSize = bounds.size.x;
if (bounds.size.z > maxSize) maxSize = bounds.size.z;
cam.orthographicSize = maxSize / 2;
cam.nearClipPlane = 0;
cam.farClipPlane = (bounds.size.y + 256);
}
public float GetHeight(Vector3 pos)
{
pos -= bounds.min;
pos.x += (maxSize - bounds.size.x) / 2;
pos.z += (maxSize - bounds.size.z) / 2;
float xx = maxSize / (resolution.x);
float yy = maxSize / (resolution.y);
float x = (int)(pos.x / xx);
float y = (int)(pos.z / yy);
if (x > resolution.x - 2 || x < 0 || y > resolution.y - 2 || y < 0)
{
Debug.Log("Out of bounds " + x + " " + y);
return 0;
}
int intX = (int)x;
int intY = (int)y;
float lerpValue = x - intX;
float height0 = heights[intX + (intY * resolution.y)];
float height1 = heights[intX + 1 + (intY * resolution.y)];
float heightx1 = Mathf.Lerp(height0, height1, lerpValue);
height0 = heights[intX + ((intY + 1) * resolution.y)];
height1 = heights[intX + 1 + ((intY + 1) * resolution.y)];
float heightx2 = Mathf.Lerp(height0, height1, lerpValue);
lerpValue = y - intY;
return Mathf.Lerp(heightx1, heightx2, lerpValue);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5118f6ea05613d14b899e139ed9dcbff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,274 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class CombinedLODManager : MonoBehaviour
{
public enum LodMode { Automatic, DebugLod }
public enum LodDistanceMode { Automatic, Manual }
public bool drawGizmos = true;
public LOD[] lods;
public float[] distances;
public LodDistanceMode lodDistanceMode;
public LodMode lodMode;
public int showLod = 0;
public bool lodCulled;
public float lodCullDistance = 500;
public Vector3 octreeCenter = Vector3.zero;
public Vector3 octreeSize = new Vector3(256, 256, 256);
public int maxLevels = 4;
public bool search = true;
Cell octree;
Transform cameraMainT;
void Awake()
{
cameraMainT = Camera.main.transform;
}
void InitOctree()
{
octree = new Cell(octreeCenter, octreeSize, maxLevels);
}
private void Start()
{
if (search)
{
search = false;
InitOctree();
Search();
}
}
void Update()
{
if (octree.cellsUsed != null) Lod(lodMode);
}
public void UpdateLods(MeshCombiner meshCombiner, int lodAmount)
{
if (lods != null && lods.Length == lodAmount) return;
lods = new LOD[lodAmount];
float[] newDistances = new float[lodAmount];
for (int i = 0; i < lods.Length; i++)
{
lods[i] = new LOD();
if (lodDistanceMode == LodDistanceMode.Automatic) newDistances[i] = meshCombiner.cellSize * i;
else if (distances != null && i < distances.Length) newDistances[i] = distances[i];
}
distances = newDistances;
}
public void UpdateDistances(MeshCombiner meshCombiner)
{
if (lodDistanceMode != LodDistanceMode.Automatic) return;
for (int i = 0; i < distances.Length; i++) distances[i] = meshCombiner.cellSize * i;
}
public void Search()
{
for (int i = 0; i < lods.Length; i++)
{
lods[i].searchParent.gameObject.SetActive(true);
MeshRenderer[] mrs = lods[i].searchParent.GetComponentsInChildren<MeshRenderer>();
for (int j = 0; j < mrs.Length; j++) octree.AddMeshRenderer(mrs[j], mrs[j].transform.position, i, lods.Length);
}
}
public void ResetOctree()
{
if (octree == null) return;
octree.cells = null;
octree.cellsUsed = null;
for (int i = 0; i < lods.Length; i++)
{
if (lods[i].searchParent != null) Destroy(lods[i].searchParent.gameObject);
}
}
public void Lod(LodMode lodMode)
{
Vector3 cameraPosition = cameraMainT.position;
for (int i = 0; i < lods.Length - 1; i++)
{
lods[i].sphere.center = cameraPosition;
lods[i].sphere.radius = distances[i + 1];
}
// if (Benchmark.active) lodBenchmark.Start();
if (lodMode == LodMode.Automatic) octree.AutoLodInternal(lods, lodCulled ? lodCullDistance : -1);
else octree.LodInternal(lods, showLod);
// if (Benchmark.active) lodBenchmark.Stop();
}
private void OnDrawGizmosSelected()
{
if (drawGizmos && octree != null && octree.cells != null) octree.DrawGizmos(lods);
}
[System.Serializable]
public class LOD
{
public Transform searchParent;
public Sphere3 sphere = new Sphere3();
public LOD() { }
public LOD(Transform searchParent)
{
this.searchParent = searchParent;
}
}
public class Cell : BaseOctree.Cell
{
public Cell[] cells;
AABB3 box;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels) : base(position, size, maxLevels) { }
public void AddMeshRenderer(MeshRenderer mr, Vector3 position, int lodLevel, int lodLevels)
{
if (InsideBounds(position)) AddMeshRendererInternal(mr, position, lodLevel, lodLevels);
}
void AddMeshRendererInternal(MeshRenderer mr, Vector3 position, int lodLevel, int lodLevels)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.mrList == null) thisCell.mrList = new List<MeshRenderer>[lodLevels];
List<MeshRenderer>[] mrList = thisCell.mrList;
if (mrList[lodLevel] == null) mrList[lodLevel] = new List<MeshRenderer>();
mrList[lodLevel].Add(mr);
thisCell.currentLod = -1;
}
else
{
bool maxCellCreated;
int index = AddCell<Cell, MaxCell>(ref cells, position, out maxCellCreated);
cells[index].box = new AABB3(cells[index].bounds.min, cells[index].bounds.max);
cells[index].AddMeshRendererInternal(mr, position, lodLevel, lodLevels);
}
}
public void AutoLodInternal(LOD[] lods, float lodCulledDistance)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (lodCulledDistance != -1)
{
float squareDistance = (bounds.center - lods[0].sphere.center).sqrMagnitude;
if (squareDistance > lodCulledDistance * lodCulledDistance)
{
if (thisCell.currentLod != -1)
{
for (int i = 0; i < lods.Length; i++)
{
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = false;
}
thisCell.currentLod = -1;
}
return;
}
}
for (int lodIndex = 0; lodIndex < lods.Length; lodIndex++)
{
bool intersect;
if (lodIndex < lods.Length - 1) intersect = Mathw.IntersectAABB3Sphere3(box, lods[lodIndex].sphere);
else intersect = true;
if (intersect)
{
if (thisCell.currentLod != lodIndex)
{
for (int i = 0; i < lods.Length; i++)
{
bool active = (i == lodIndex);
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = active;
}
thisCell.currentLod = lodIndex;
}
break;
}
}
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].AutoLodInternal(lods, lodCulledDistance);
}
public void LodInternal(LOD[] lods, int lodLevel)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.currentLod != lodLevel)
{
for (int i = 0; i < lods.Length; i++)
{
bool active = (i == lodLevel);
for (int j = 0; j < thisCell.mrList[i].Count; j++) thisCell.mrList[i][j].enabled = active;
}
thisCell.currentLod = lodLevel;
}
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].LodInternal(lods, lodLevel);
} //===============================================================================================================================
public void DrawGizmos(LOD[] lods)
{
for (int i = 0; i < lods.Length; i++)
{
if (i == 0) Gizmos.color = Color.red;
else if (i == 1) Gizmos.color = Color.green;
else if (i == 2) Gizmos.color = Color.yellow;
else if (i == 3) Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(lods[i].sphere.center, lods[i].sphere.radius);
}
DrawGizmosInternal();
}
public void DrawGizmosInternal()
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.currentLod == 0) Gizmos.color = Color.red;
else if (thisCell.currentLod == 1) Gizmos.color = Color.green;
else if (thisCell.currentLod == 2) Gizmos.color = Color.yellow;
else if (thisCell.currentLod == 3) Gizmos.color = Color.blue;
Gizmos.DrawWireCube(bounds.center, bounds.size - new Vector3(0.25f, 0.25f, 0.25f));
Gizmos.color = Color.white;
}
else for (int i = 0; i < 8; ++i) if (cellsUsed[i]) cells[i].DrawGizmosInternal();
}
}
public class MaxCell : Cell
{
public List<MeshRenderer>[] mrList;
public int currentLod;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 01b543286c6d4484c9335dbf57a0b586
timeCreated: 1496162540
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ListMeshVertCount : MonoBehaviour {
public bool includeInActive;
public bool listVertCount;
void Update()
{
if (listVertCount)
{
listVertCount = false;
ListVertCount();
}
}
void ListVertCount()
{
MeshFilter[] mfs = GetComponentsInChildren<MeshFilter>(includeInActive);
int vertCount = 0;
int triangleCount = 0;
for (int i = 0; i < mfs.Length; i++)
{
Mesh m = mfs[i].sharedMesh;
if (m == null) continue;
vertCount += m.vertexCount;
triangleCount += m.triangles.Length;
}
Debug.Log(gameObject.name + " Vertices " + vertCount + " Triangles " + triangleCount);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d9eaad923cc4fca4396a6e2ec092b9e9
timeCreated: 1507213037
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 409bc0be2fd0301499c7685349d5eef7
timeCreated: 1509346503
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c7fb52db265e28e4eb22d6300d01e030
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,111 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
[ExecuteInEditMode]
public class ObjectSpawner : MonoBehaviour
{
public GameObject[] objects;
public float density = 0.5f;
public Vector2 scaleRange = new Vector2(0.5f, 2f);
public Vector3 rotationRange = new Vector3(5, 360, 5);
public Vector2 heightRange = new Vector2(0, 1);
public float scaleMulti = 1;
public float resolutionPerMeter = 2;
public bool spawnInRuntime;
public bool spawn;
public bool deleteChildren;
Transform t;
private void Awake()
{
t = transform;
if (spawnInRuntime && Application.isPlaying)
{
Spawn();
}
}
private void Update()
{
if (spawn)
{
spawn = false;
Spawn();
}
if (deleteChildren)
{
deleteChildren = false;
DeleteChildren();
}
}
public void DeleteChildren()
{
Transform[] transforms = GetComponentsInChildren<Transform>();
for (int i = 0; i < transforms.Length; i++)
{
if (t != transforms[i] && transforms[i] != null) DestroyImmediate(transforms[i].gameObject);
}
}
public void Spawn()
{
Bounds bounds = new Bounds();
bounds.center = transform.position;
bounds.size = transform.lossyScale;
float xStart = bounds.min.x;
float xEnd = bounds.max.x;
float yStart = bounds.min.y;
float yEnd = bounds.max.y;
float zStart = bounds.min.z;
float zEnd = bounds.max.z;
int objectCount = objects.Length;
float halfRes = resolutionPerMeter * 0.5f;
float heightOffset = transform.lossyScale.y * 0.5f;
int count = 0;
for (float z = zStart; z < zEnd; z += resolutionPerMeter)
{
for (float x = xStart; x < xEnd; x += resolutionPerMeter)
{
for (float y = yStart; y < yEnd; y += resolutionPerMeter)
{
int index = Random.Range(0, objectCount);
float spawnValue = Random.value;
if (spawnValue < density)
{
Vector3 pos = new Vector3(x + Random.Range(-halfRes, halfRes), yStart + (Random.Range(0, bounds.size.y) * Random.Range(heightRange.x, heightRange.y)), z + Random.Range(-halfRes, halfRes));
if (pos.x < xStart || pos.x > xEnd || pos.y < yStart || pos.y > yEnd || pos.z < zStart || pos.z > zEnd) continue;
pos.y += heightOffset;
Vector3 eulerAngles = new Vector3(Random.Range(0, rotationRange.x), Random.Range(0, rotationRange.y), Random.Range(0, rotationRange.z));
GameObject go = (GameObject)Instantiate(objects[index], pos, Quaternion.Euler(eulerAngles));
float scale = Random.Range(scaleRange.x, scaleRange.y) * scaleMulti;
go.transform.localScale = new Vector3(scale, scale, scale);
go.transform.parent = t;
++count;
}
}
}
}
Debug.Log("Spawned " + count);
}
private void OnDrawGizmosSelected()
{
Gizmos.DrawWireCube(transform.position + new Vector3(0, transform.lossyScale.y * 0.5f, 0), transform.lossyScale);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 80e3d5613a0399b4b87617ecc61c7c94
timeCreated: 1505205806
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,276 @@
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;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f47068a0804dcdf41a46c89f754480ed
timeCreated: 1496067184
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MeshCombineStudio
{
public class SwapCombineKey : MonoBehaviour
{
static public SwapCombineKey instance;
public List<MeshCombiner> meshCombinerList = new List<MeshCombiner>();
MeshCombiner meshCombiner;
GUIStyle textStyle;
void Awake()
{
instance = this;
meshCombiner = GetComponent<MeshCombiner>();
meshCombinerList.Add(meshCombiner);
}
void OnDestroy()
{
instance = null;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
QualitySettings.vSyncCount = 0;
meshCombiner.SwapCombine();
}
}
private void OnGUI()
{
if (textStyle == null)
{
textStyle = new GUIStyle("label");
textStyle.fontStyle = FontStyle.Bold;
textStyle.fontSize = 16;
}
textStyle.normal.textColor = this.meshCombiner.combinedActive ? Color.green : Color.red;
GUI.Label(new Rect(10, 45 + (meshCombinerList.Count * 22), 200, 30), "Toggle with 'Tab' key.", textStyle);
for (int i = 0; i < meshCombinerList.Count; i++)
{
MeshCombiner meshCombiner = meshCombinerList[i];
if (meshCombiner.combinedActive) GUI.Label(new Rect(10, 30 + (i * 22), 300, 30), meshCombiner.gameObject.name + " is Enabled.", textStyle);
else GUI.Label(new Rect(10, 30 + (i * 22), 300, 30), meshCombiner.gameObject.name + " is Disabled.", textStyle);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3c430fd3101f200428cac71e6b69b0dc
timeCreated: 1505065196
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,372 @@
//using System.Collections;
//using System.Collections.Generic;
//using UnityEngine;
//using MeshCombineStudio;
//using System;
//namespace MeshCombineStudio
//{
// static public class Voxelize
// {
// static readonly byte[] bits = new byte[] { 1, 2, 4, 8, 16, 32, 64, 128 };
// static Dictionary<Mesh, VoxelizedMesh> voxelizedLookup = new Dictionary<Mesh, VoxelizedMesh>();
// static List<float> intersectList = new List<float>();
// const byte insideVoxel = 1;
// const byte outsideVoxel = 2;
// public class VoxelizedMesh
// {
// public byte[,,] volume;
// public Bounds bounds;
// public Int3 voxels;
// }
// static VoxelizedMesh VoxelizeMesh(Transform t, float voxelResolution, int voxelizeLayer)
// {
// // TODO ray cast from right/left and top/down
// MeshRenderer mr = t.GetComponent<MeshRenderer>();
// if (mr == null) return null;
// MeshFilter mf = t.GetComponent<MeshFilter>();
// if (mf == null) return null;
// Mesh mesh = mf.sharedMesh;
// if (mesh == null) return null;
// VoxelizedMesh vm = new VoxelizedMesh();
// voxelizedLookup.Add(mesh, vm);
// Transform oldParent = t.parent;
// Vector3 oldPos = t.position;
// Quaternion oldRot = t.rotation;
// Vector3 oldScale = t.localScale;
// t.parent = null;
// t.position = Vector3.zero;
// t.rotation = Quaternion.identity;
// t.localScale = Vector3.one;
// int oldLayer = t.gameObject.layer;
// t.gameObject.layer = voxelizeLayer;
// LayerMask voxelizeLayerMask = 1 << voxelizeLayer;
// Bounds bounds = mr.bounds;
// Vector3 size = bounds.size;
// Int3 voxels = new Int3(Mathf.CeilToInt(size.x / voxelResolution), Mathf.CeilToInt(size.y / voxelResolution), Mathf.CeilToInt(size.z / voxelResolution));
// voxels += new Int3(2, 2, 2);
// int voxelsX = Mathf.CeilToInt(voxels.x / 8f);
// vm.voxels = voxels;
// size = new Vector3(voxels.x * voxelResolution, voxels.y * voxelResolution, voxels.z * voxelResolution);
// bounds.size = size;
// vm.bounds = bounds;
// byte[,,] volume = new byte[voxelsX, voxels.y, voxels.z];
// Ray ray = new Ray();
// Ray ray2 = new Ray();
// ray.direction = Vector3.forward;
// ray2.direction = Vector3.back;
// Vector3 pos = bounds.min;
// Vector3 pos2 = pos;
// pos2.z = bounds.max.z;
// // Debug.Log(PrintVector3(mr.bounds.size) + " new size " + PrintVector3(size) + " voxels " + voxels);
// int voxelCount = 0;
// Vector3 halfVoxel = Vector3.one * voxelResolution * 0.5f;
// Vector3 minBoundsVoxel = pos + halfVoxel;
// try
// {
// for (int x = 0; x < voxels.x; x++)
// {
// int xGrid = x / 8;
// byte bit = bits[x - (xGrid * 8)];
// for (int y = 0; y < voxels.y; y++)
// {
// Vector3 origin = pos + new Vector3((x + 0.5f) * voxelResolution, (y + 0.5f) * voxelResolution, 0);
// ray.origin = origin;
// origin.z = pos2.z;
// ray2.origin = origin;
// intersectList.Clear();
// MultiCast(ray, intersectList, 0.001f, size.z, voxelizeLayerMask);
// MultiCast(ray2, intersectList, -0.001f, size.z, voxelizeLayerMask);
// intersectList.Sort();
// float half = (float)intersectList.Count / 2;
// if (half != (int)half) { continue; }
// // Debug.Log(hitInfos.Length +" " + hitInfos2.Length +" " + list.Count);
// for (int i = 0; i < intersectList.Count; i += 2)
// {
// int z1 = Mathf.RoundToInt((intersectList[i] - pos.z) / voxelResolution);
// int z2 = Mathf.RoundToInt((intersectList[i + 1] - pos.z) / voxelResolution);
// for (int z = z1; z < z2; z++)
// {
// Vector3 voxelPos = new Vector3(x * voxelResolution, y * voxelResolution, z * voxelResolution) + minBoundsVoxel;
// voxelPos = t.TransformPoint(voxelPos);
// // volume[xGrid, y, z] |= bit;
// // if (!Physics.CheckBox(voxelPos, halfVoxel, Quaternion.identity, voxelizeLayerMask))
// {
// volume[xGrid, y, z] |= bit;
// ++voxelCount;
// }
// }
// }
// }
// }
// }
// catch (Exception e)
// {
// Debug.LogError(e.ToString());
// }
// // Debug.Log(t.name + " voxels " + voxelCount);
// vm.volume = volume;
// t.gameObject.layer = oldLayer;
// t.parent = oldParent;
// t.position = oldPos;
// t.rotation = oldRot;
// t.localScale = oldScale;
// return vm;
// }
// static string PrintVector3(Vector3 v)
// {
// return "(" + v.x + ", " + v.y + ", " + v.z + ")";
// }
// static void MultiCast(Ray ray, List<float> points, float hitOffset, float maxDistance, LayerMask voxelizeLayerMask)
// {
// RaycastHit hitInfo;
// while (Physics.Raycast(ray, out hitInfo, maxDistance, voxelizeLayerMask))
// {
// points.Add(hitInfo.point.z);
// Vector3 origin = ray.origin;
// ray.origin = new Vector3(origin.x, origin.y, hitInfo.point.z + hitOffset);
// }
// }
// static void Report(VoxelizedMesh vm, float voxelResolution)
// {
// int voxelResolutionX = (int)voxelResolution / 8;
// for (int x = 0; x < voxelResolutionX; x++)
// {
// for (int y = 0; y < voxelResolution; y++)
// {
// for (int z = 0; z < voxelResolution; z++)
// {
// Debug.Log(vm.volume[x, y, z]);
// }
// }
// }
// }
// static public void RemoveOverlap(Transform t, MeshCombineJobManager.MeshCombineJob meshCombineJob, MeshCache.SubMeshCache newMeshCache, ref byte[] vertexIsInsideVoxels)
// {
// if (vertexIsInsideVoxels == null) vertexIsInsideVoxels = new byte[65534];
// float voxelResolution = meshCombineJob.meshCombiner.voxelResolution;
// int voxelizeLayer = meshCombineJob.meshCombiner.voxelizeLayer;
// Vector3[] newVertices = newMeshCache.vertices;
// int[] newTriangles = newMeshCache.triangles;
// List<MeshObject> meshObjects = meshCombineJob.meshObjectsHolder.meshObjects;
// int startIndex = meshCombineJob.startIndex;
// int endIndex = meshCombineJob.endIndex;
// for (int a = startIndex; a < endIndex; a++)
// {
// MeshObject meshObject = meshObjects[a];
// CachedGameObject cachedGO = meshObject.cachedGO;
// // Get array of intersections
// // Bounds bounds = cachedGO.mr.bounds;
// Collider[] colliders = null;//!! Physics.OverlapBox(bounds.center, bounds.extents, Quaternion.identity, meshCombineJob.meshCombiner.overlapLayerMask);
// if (colliders.Length == 0)
// {
// // Debug.Log("No overlap " + cachedGO.go.name);
// continue;
// }
// // Debug.Log("Overlaps " + colliders.Length);
// Transform[] colliderTs = new Transform[colliders.Length];
// VoxelizedMesh[] colliderVms = new VoxelizedMesh[colliders.Length];
// for (int i = 0; i < colliderVms.Length; i++)
// {
// colliderTs[i] = colliders[i].transform;
// if (colliderTs[i] == cachedGO.t) continue;
// MeshFilter mf = colliderTs[i].GetComponent<MeshFilter>();
// if (mf == null) continue;
// Mesh mesh = mf.sharedMesh;
// if (mesh == null) continue;
// voxelizedLookup.TryGetValue(mesh, out colliderVms[i]);
// if (colliderVms[i] == null) colliderVms[i] = VoxelizeMesh(colliderTs[i], voxelResolution, voxelizeLayer);
// // Debug.LogError("Couldn't find voxelized mesh for " + mo.m + " " + child.name);
// }
// float invVoxelResolution = 1 / voxelResolution;
// int startTriangleIndex = meshObject.startNewTriangleIndex;
// int endTriangleIndex = meshObject.newTriangleCount + startTriangleIndex;
// // Debug.Log("start " + startTriangleIndex + " end " + endTriangleIndex);
// for (int i = startTriangleIndex; i < endTriangleIndex; i += 3)
// {
// bool insideAllVoxels = true;
// for (int k = 0; k < 3; k++)
// {
// int vertexIndex = newTriangles[i + k];
// if (vertexIndex == -1) continue;
// byte isInsideVoxel = vertexIsInsideVoxels[vertexIndex];
// if (isInsideVoxel == 0)
// {
// bool inside = false;
// for (int j = 0; j < colliders.Length; j++)
// {
// Transform colliderT = colliderTs[j];
// VoxelizedMesh colliderVm = colliderVms[j];
// if (colliderVm == null) continue;
// Vector3 boundsMin = colliderVm.bounds.min;
// Vector3 vertPos = t.TransformPoint(newVertices[vertexIndex]);
// Vector3 pos = colliderT.InverseTransformPoint(vertPos) - boundsMin;
// Vector3 grid = new Vector3(pos.x * invVoxelResolution, pos.y * invVoxelResolution, pos.z * invVoxelResolution);
// if (grid.x < 0 || grid.x >= colliderVm.voxels.x || grid.y < 0 || grid.y >= colliderVm.voxels.y || grid.z < 0 || grid.z >= colliderVm.voxels.z) continue;
// int xGrid = (int)grid.x;
// int xxGrid = xGrid / 8;
// byte bit = bits[(xGrid - (xxGrid * 8))];
// if ((colliderVm.volume[xxGrid, (int)grid.y, (int)grid.z] & bit) == 0) continue;
// inside = true;
// break;
// }
// vertexIsInsideVoxels[vertexIndex] = isInsideVoxel = (inside ? insideVoxel : outsideVoxel);
// }
// if (isInsideVoxel == outsideVoxel)
// {
// insideAllVoxels = false;
// break;
// }
// }
// if (insideAllVoxels)
// {
// meshCombineJob.trianglesRemoved += 3;
// newTriangles[i] = -1;
// }
// }
// }
// Array.Clear(vertexIsInsideVoxels, 0, newMeshCache.vertexCount);
// // Debug.Log("Removed " + meshCombineJob.trianglesRemoved);
// newMeshCache.triangles = newTriangles;
// }
// static public void DrawGizmos(GameObject go, float voxelResolution)
// {
// Transform[] ts = go.GetComponentsInChildren<Transform>();
// Gizmos.color = Color.red;
// for (int i = 0; i < ts.Length; i++) DrawVolume(ts[i], voxelResolution);
// Gizmos.color = Color.white;
// }
// static public void DrawVolume(Transform t, float voxelResolution)
// {
// MeshRenderer mr = t.GetComponent<MeshRenderer>();
// if (mr == null) return;
// MeshFilter mf = t.GetComponent<MeshFilter>();
// if (mf == null) return;
// Mesh m = mf.sharedMesh;
// if (m == null) return;
// VoxelizedMesh vm;
// voxelizedLookup.TryGetValue(m, out vm);
// if (vm == null) return;
// byte[,,] volume = vm.volume;
// if (volume == null) return;
// Vector3 pos = vm.bounds.min;
// Vector3 voxel = t.lossyScale * voxelResolution;
// Vector3 halfVoxel = Vector3.one * voxelResolution * 0.5f;
// Int3 voxels = vm.voxels;
// // Debug.Log(voxels);
// // Debug.Log(volume.Length);
// Gizmos.DrawWireCube(mr.bounds.center, mr.bounds.size);
// for (int x = 0; x < voxels.x; x++)
// {
// int xGrid = x / 8;
// int bit = x - (xGrid * 8);
// for (int y = 0; y < voxels.y; y++)
// {
// for (int z = 0; z < voxels.z; z++)
// {
// if ((volume[xGrid, y, z] & bits[bit]) > 0)
// {
// Vector3 localPos = new Vector3(pos.x + (x * voxelResolution), pos.y + (y * voxelResolution), pos.z + (z * voxelResolution)) + halfVoxel;
// Gizmos.DrawWireCube(t.TransformPoint(localPos), voxel);
// }
// }
// }
// }
// }
// }
//}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1abfeedba8fba6241b5632cfa2ad5222
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: