Files
2026-02-21 16:45:37 +08:00

116 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace Mtree
{
public static class DensityAO
{
private static void BakeAo(Color[] colors, Vector3[] verts, Vector3[] normals, int[] triangles, Matrix4x4 transform, float resolution, float distance, string TreeName)
{
float[] array = new float[triangles.Length / 3];
float num = 0f;
for (int i = 0; i < triangles.Length; i += 3)
{
array[i / 3] = GetTriangleArea(verts[triangles[i]], verts[triangles[i + 1]], verts[triangles[i + 2]]);
num += array[i / 3];
}
for (int j = 0; j < array.Length; j++)
{
array[j] /= num;
}
List<Vector3> list = new List<Vector3>();
WeightedRandom weightedRandom = new WeightedRandom(array);
int num2 = (int)(num / (resolution * resolution));
System.Random random = new System.Random();
for (int k = 0; k < num2; k++)
{
int randomIndex = weightedRandom.GetRandomIndex(random);
Vector3 point = SamplePointInTriangle(verts[triangles[randomIndex * 3]], verts[triangles[randomIndex * 3 + 1]], verts[triangles[randomIndex * 3 + 2]], random);
point = transform.MultiplyPoint3x4(point);
list.Add(point);
}
KDTree kDTree = new KDTree(list.ToArray(), transform.MultiplyPoint3x4(Vector3.zero), TreeName);
float[] array2 = new float[verts.Length];
float num3 = 0f;
for (int l = 0; l < verts.Length; l++)
{
Vector3 vector = transform.MultiplyPoint3x4(verts[l]);
List<Vector3> list2 = kDTree.RadiusSearch(vector, distance);
float num4 = 0f;
Vector3 lhs = transform.MultiplyVector(normals[l]);
foreach (Vector3 item in list2)
{
float num5 = Vector3.Distance(item, vector);
num4 += Mathf.Clamp01(Vector3.Dot(lhs, item - vector) / num5 + 0.5f) * Mathf.Exp(0f - num5);
}
num3 = Mathf.Max(num4, num3);
array2[l] = num4;
}
for (int m = 0; m < array2.Length; m++)
{
array2[m] /= num3;
}
for (int n = 0; n < colors.Length; n++)
{
colors[n].a = Mathf.Pow(1f - array2[n], 5f);
}
}
public static float GetTriangleArea(Vector3 v1, Vector3 v2, Vector3 v3)
{
Vector3 lhs = v2 - v1;
Vector3 rhs = v3 - v1;
return Vector3.Cross(lhs, rhs).magnitude / 2f;
}
private static Vector3 SamplePointInTriangle(Vector3 v1, Vector3 v2, Vector3 v3, System.Random random)
{
float f = (float)random.NextDouble();
float num = (float)random.NextDouble();
return (1f - Mathf.Sqrt(f)) * v1 + Mathf.Sqrt(f) * (1f - num) * v2 + num * Mathf.Sqrt(f) * v3;
}
public static ThreadHandleEditor BakeAoAsync(MeshFilter meshFilter, GameObject ob, float resolution, float distance)
{
Mesh mesh = meshFilter.sharedMesh;
Color[] colors = mesh.colors;
Vector3[] verts = mesh.vertices;
Vector3[] normals = mesh.normals;
int[] triangles = mesh.triangles;
string name = ob.name;
if (meshFilter == null || ob == null)
{
return null;
}
Matrix4x4 transformMatrix = ob.transform.localToWorldMatrix;
ThreadHandleEditor threadHandleEditor = new ThreadHandleEditor(null, delegate
{
BakeAo(colors, verts, normals, triangles, transformMatrix, resolution, distance, name);
}, delegate
{
mesh.colors = colors;
if (meshFilter != null)
{
meshFilter.sharedMesh = mesh;
}
});
threadHandleEditor.Start();
return threadHandleEditor;
}
public static void BakeAo(MeshFilter meshFilter, GameObject ob, float resolution, float distance)
{
Mesh sharedMesh = meshFilter.sharedMesh;
Color[] colors = sharedMesh.colors;
Vector3[] vertices = sharedMesh.vertices;
Vector3[] normals = sharedMesh.normals;
int[] triangles = sharedMesh.triangles;
Matrix4x4 localToWorldMatrix = ob.transform.localToWorldMatrix;
BakeAo(colors, vertices, normals, triangles, localToWorldMatrix, resolution, distance, ob.name);
sharedMesh.colors = colors;
meshFilter.sharedMesh = sharedMesh;
}
}
}