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

264 lines
8.3 KiB
C#

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;
FastList<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.items[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);
}
}
}