Files
KopMap/Assets/NatureManufacture Assets/WorldStreamer/Scritps/Terrain/MeshDrawerInstance.cs
2025-09-02 18:55:19 +08:00

282 lines
8.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace WorldStreamer2
{
[ExecuteInEditMode]
public class MeshDrawerInstance : MonoBehaviour
{
public bool noFrustrum = true;
//public Mesh mesh;
public MeshDistance[] meshDistances;
public Matrix4x4[] matrices;
//public Material material;
public List<Dictionary<Vector3Int, Cell>> cells;
void Start()
{
GenerateCells();
}
private void GenerateCells()
{
//int[] posInt = new int[] { posX, posY, posZ };
// new Dictionary<int[], SceneSplit>(new IntArrayComparer());
cells = new List<Dictionary<Vector3Int, Cell>>();
Vector3 pos;
for (int m = 0; m < meshDistances.Length; m++)
{
cells.Add(new Dictionary<Vector3Int, Cell>(new Vector3IntArrayComparer()));
float cellSize = meshDistances[m].cellSize;
for (int i = 0; i < matrices.Length; i++)
{
pos = matrices[i].GetColumn(3);
int x = (int)Mathf.FloorToInt((pos.x / cellSize));
int z = (int)Mathf.FloorToInt((pos.z / cellSize));
Vector3Int cellID = new Vector3Int(x, 0, z);
if (cells[m].ContainsKey(cellID))
{
cells[m][cellID].matrices.Add(matrices[i]);
cells[m][cellID].bounds.Encapsulate(pos);
if (cells[m][cellID].size.x > pos.x)
{
cells[m][cellID].size.x = pos.x;
}
if (cells[m][cellID].size.y < pos.x)
{
cells[m][cellID].size.y = pos.x;
}
if (cells[m][cellID].size.z > pos.z)
{
cells[m][cellID].size.z = pos.z;
}
if (cells[m][cellID].size.w < pos.z)
{
cells[m][cellID].size.w = pos.z;
}
}
else
{
cells[m].Add(cellID, new Cell()
{
matrices = new List<Matrix4x4>(),
size = new Vector4(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue),
bounds = new Bounds()
});
cells[m][cellID].matrices.Add(matrices[i]);
cells[m][cellID].bounds.Encapsulate(pos);
if (cells[m][cellID].size.x > pos.x)
{
cells[m][cellID].size.x = pos.x;
}
if (cells[m][cellID].size.y < pos.x)
{
cells[m][cellID].size.y = pos.x;
}
if (cells[m][cellID].size.z > pos.z)
{
cells[m][cellID].size.z = pos.z;
}
if (cells[m][cellID].size.w < pos.z)
{
cells[m][cellID].size.w = pos.z;
}
}
}
foreach (var item in cells[m].Keys)
{
cells[m][item].matricesArray = cells[m][item].matrices.ToArray();
}
}
}
// Update is called once per frame
void Update()
{
Camera mainCam = Camera.main;
Vector3 pos = mainCam.transform.position;
if (meshDistances == null)
return;
if (cells == null || cells.Count == 0)
{
GenerateCells();
return;
}
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(mainCam);
for (int i = 0; i < meshDistances.Length; i++)
{
if (!meshDistances[i].on)
continue;
float cellSize = meshDistances[i].cellSize;
int distanceCell = (int)Mathf.FloorToInt((meshDistances[i].distance / (float)cellSize)) + 1;
if (distanceCell > 100)
return;
int previousDistCell = 0;
if (i > 0)
previousDistCell = (int)Mathf.FloorToInt((meshDistances[i - 1].distance * 2 / (float)cellSize));
int x = (int)Mathf.FloorToInt((pos.x / cellSize));
int z = (int)Mathf.FloorToInt((pos.z / cellSize));
Vector3Int cameraCellID = new Vector3Int(x, 0, z);
Vector3Int cellId = cameraCellID;
for (int posX = x - distanceCell; posX < x + distanceCell; posX++)
{
for (int posZ = z - distanceCell; posZ < z + distanceCell; posZ++)
{
cellId.x = posX;
cellId.z = posZ;
if (Mathf.Abs(posX - x) < previousDistCell && Mathf.Abs(posZ - z) < previousDistCell)
continue;
if (cells[i].ContainsKey(cellId))
for (int j = 0; j < meshDistances[i].meshMaterials.Count; j++)
{
MeshMaterials meshMaterial = meshDistances[i].meshMaterials[j];
bool render = true;
render = GeometryUtility.TestPlanesAABB(planes, cells[i][cellId].bounds);
if (render || noFrustrum)
{
for (int m = 0; m < meshMaterial.materials.Length; m++)
{
Graphics.DrawMeshInstanced(meshMaterial.mesh, m, meshMaterial.materials[m], cells[i][cellId].matricesArray);
}
}
}
}
}
}
}
void OnDrawGizmosSelected()
{
// return;
Vector3 pos = Camera.main.transform.position;
Gizmos.color = Color.red;
Gizmos.DrawSphere(pos, 5);
Color[] colors = new Color[] { Color.red, Color.green, Color.blue, Color.cyan, Color.magenta };
for (int i = meshDistances.Length - 1; 0 <= i; i--)
{
Gizmos.color = Color.yellow;
//continue;
if (!meshDistances[i].on)
continue;
Gizmos.DrawWireCube(pos, Vector3.one * meshDistances[i].distance);
float cellSize = meshDistances[i].cellSize;
int distanceCell = (int)Mathf.FloorToInt((meshDistances[i].distance / (float)cellSize)) + 1;
if (distanceCell > 20)
return;
int previousDistCell = 0;
if (i > 0)
previousDistCell = (int)Mathf.FloorToInt((meshDistances[i - 1].distance * 2 / (float)cellSize));
int x = (int)Mathf.FloorToInt((pos.x / cellSize));
int z = (int)Mathf.FloorToInt((pos.z / cellSize));
Vector2Int cameraCellID = new Vector2Int(x, z);
Vector2Int cellId = cameraCellID;
for (int posX = x - distanceCell; posX < x + distanceCell; posX++)
{
for (int posY = z - distanceCell; posY < z + distanceCell; posY++)
{
cellId.x = posX;
cellId.y = posY;
Gizmos.color = colors[i];
// Debug.Log(previousDistCell);
if (Mathf.Abs(posX - x) < previousDistCell && Mathf.Abs(posY - z) < previousDistCell)
{
continue;
}
Gizmos.DrawWireCube(new Vector3(posX * cellSize + cellSize * 0.5f, pos.y, posY * cellSize + cellSize * 0.5f), Vector3.one * cellSize);
}
}
}
}
}
[System.Serializable]
public class MeshDistance
{
public List<MeshMaterials> meshMaterials;
public float distance = 1000;
public float cellSize = 10;
public bool on = true;
}
[System.Serializable]
public class Cell
{
public List<Matrix4x4> matrices;
public Matrix4x4[] matricesArray;
public Bounds bounds;
public Vector4 size;
}
[System.Serializable]
public class MeshMaterials
{
public Mesh mesh;
public Material[] materials;
}
}