TG9six 03a642d635 first push
first push
2025-09-06 17:17:39 +04:00

204 lines
6.7 KiB
C#

// Perfect Culling (C) 2021 Patrick König
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace Koenigz.PerfectCulling
{
public class PerfectCullingMeshSplitting
{
private const int SplitSize = 8000;
class SplitMeshData
{
public List<int> indices = new List<int>();
public List<Vector3> verts = new List<Vector3>();
public List<Color> colors = new List<Color>();
public List<TriangleData> tris = new List<TriangleData>();
public Mesh CreateMesh()
{
Mesh newMesh = new Mesh();
newMesh.indexFormat = IndexFormat.UInt32;
newMesh.SetVertices(verts);
newMesh.SetTriangles(indices, 0);
newMesh.SetColors(colors);
#if UNITY_EDITOR
UnityEditor.MeshUtility.Optimize(newMesh);
#endif
return newMesh;
}
}
class TriangleData
{
public Vector3 posA;
public Vector3 posB;
public Vector3 posC;
public Color colA;
//public Color colB;
//public Color colC;
public Vector3 center;
}
public static List<Mesh> Split(Mesh mesh, Matrix4x4 transformMatrix)
{
List<Mesh> splitMeshes = new List<Mesh>();
SplitMeshData inputSM = GenerateFromMesh(mesh, transformMatrix);
inputSM.tris.Sort((a, b) => a.center.x.CompareTo(b.center.x));
foreach (SplitMeshData splitMeshesX in SplitTriangles(inputSM.tris, SplitSize * 8))
{
splitMeshesX.tris.Sort((a, b) => a.center.z.CompareTo(b.center.z));
var splitMeshesZ = SplitTriangles(splitMeshesX.tris, SplitSize);
foreach (var splitMeshData in splitMeshesZ)
{
splitMeshes.Add(splitMeshData.CreateMesh());
}
}
return splitMeshes;
}
class TupleComparer : IEqualityComparer<ValueTuple<Vector3, Color>>
{
public bool Equals(ValueTuple<Vector3, Color> x, ValueTuple<Vector3, Color> y)
{
return (x.Item1 == y.Item1) && (x.Item2 == y.Item2);
}
public int GetHashCode(ValueTuple<Vector3, Color> obj)
{
return obj.Item1.GetHashCode() ^ obj.Item2.GetHashCode();
}
}
private static TupleComparer tupleComparer = new TupleComparer();
private static List<SplitMeshData> SplitTriangles(List<TriangleData> triangles, int splitCount)
{
List<SplitMeshData> meshes = new List<SplitMeshData>();
int cIndex = 0;
Dictionary<ValueTuple<Vector3, Color>, int> spV = new Dictionary<ValueTuple<Vector3, Color>, int>(tupleComparer);
SplitMeshData splitMeshData = new SplitMeshData();
void SplitMesh()
{
int indicesCount = splitMeshData.indices.Count;
for (int i = 0; i < indicesCount; i += 3)
{
Vector3 pos1 = splitMeshData.verts[splitMeshData.indices[i + 0]];
Vector3 pos2 = splitMeshData.verts[splitMeshData.indices[i + 1]];
Vector3 pos3 = splitMeshData.verts[splitMeshData.indices[i + 2]];
splitMeshData.tris.Add(new TriangleData()
{
posA = pos1,
posB = pos2,
posC = pos3,
colA = splitMeshData.colors[splitMeshData.indices[i + 0]],
//colB = splitMeshData.colors[splitMeshData.indices[i + 1]],
//colC = splitMeshData.colors[splitMeshData.indices[i + 2]],
center = (pos1 + pos2 + pos3) / 3
});
}
meshes.Add(splitMeshData);
splitMeshData = new SplitMeshData();
spV.Clear();
cIndex = 0;
}
void AddVerts(Vector3 pos, Color col)
{
if (spV.TryGetValue(new ValueTuple<Vector3, Color>(pos, col), out int vertPosAIndex))
{
splitMeshData.indices.Add(vertPosAIndex);
}
else
{
spV.Add(new ValueTuple<Vector3, Color>(pos, col), cIndex);
splitMeshData.verts.Add(pos);
splitMeshData.indices.Add(cIndex);
splitMeshData.colors.Add(col);
++cIndex;
}
}
foreach (TriangleData tri in triangles)
{
AddVerts(tri.posA, tri.colA);
AddVerts(tri.posB, tri.colA);//tri.colB);
AddVerts(tri.posC, tri.colA);//tri.colC);
if (splitMeshData.verts.Count >= splitCount)
{
SplitMesh();
}
}
SplitMesh();
return meshes;
}
private static SplitMeshData GenerateFromMesh(Mesh mesh, Matrix4x4 transformMat)
{
SplitMeshData splitMeshData = new SplitMeshData();
Vector3[] verts = mesh.vertices;
int[] indices = mesh.GetIndices(0);
Color[] colors = mesh.colors;
bool needsMul = transformMat != Matrix4x4.identity;
int indicesLength = indices.Length;
for (int i = 0; i < indicesLength; i += 3)
{
Vector3 worldVertPosA = needsMul ? transformMat.MultiplyPoint3x4(verts[indices[i + 0]]) : verts[indices[i + 0]];
Vector3 worldVertPosB = needsMul ? transformMat.MultiplyPoint3x4(verts[indices[i + 1]]) : verts[indices[i + 1]];
Vector3 worldVertPosC = needsMul ? transformMat.MultiplyPoint3x4(verts[indices[i + 2]]) : verts[indices[i + 2]];
splitMeshData.tris.Add(new TriangleData()
{
posA = worldVertPosA,
posB = worldVertPosB,
posC = worldVertPosC,
colA = colors[indices[i + 0]],
//colB = colors[indices[i + 1]],
//colC = colors[indices[i + 2]],
center = (worldVertPosA + worldVertPosB + worldVertPosC) / 3
});
}
splitMeshData.indices = indices.ToList();
splitMeshData.verts = verts.ToList();
splitMeshData.colors = colors.ToList();
return splitMeshData;
}
}
}