211 lines
6.6 KiB
C#
211 lines
6.6 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 网格合并工具类
|
||
/// </summary>
|
||
public static class MeshCombineUtils
|
||
{
|
||
/// <summary>
|
||
/// 收集渲染器
|
||
/// </summary>
|
||
public static List<Renderer> CollectRenderers(List<Transform> roots)
|
||
{
|
||
List<Renderer> allRenderers = new();
|
||
foreach (var root in roots)
|
||
{
|
||
if (!root)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var render = root.GetComponentsInChildren<Renderer>();
|
||
if (render is not { Length: > 0 })
|
||
{
|
||
continue;
|
||
}
|
||
|
||
allRenderers.AddRange(render);
|
||
}
|
||
|
||
return allRenderers;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据相互距离对渲染器进行分组
|
||
/// 只要物体与组内任意一个物体距离小于 maxDistance,就将其加入该组
|
||
/// </summary>
|
||
public static Dictionary<string, List<Renderer>> GroupRenderersByProximity(List<Renderer> renderers,
|
||
float maxDistance)
|
||
{
|
||
var groups = new Dictionary<string, List<Renderer>>();
|
||
var groupIndex = 0;
|
||
|
||
// 已分组的渲染器
|
||
var processedRenderers = new HashSet<Renderer>();
|
||
|
||
// 对所有渲染器进行处理
|
||
while (processedRenderers.Count < renderers.Count)
|
||
{
|
||
// 找到第一个未处理的渲染器作为新组的起点
|
||
Renderer startRenderer = FindFirstUnprocessedRenderer(renderers, processedRenderers);
|
||
|
||
if (startRenderer == null)
|
||
break;
|
||
|
||
// 创建新组并添加起点渲染器
|
||
var currentGroup = new List<Renderer> { startRenderer };
|
||
processedRenderers.Add(startRenderer);
|
||
|
||
// 扩展当前组
|
||
ExpandGroupByProximity(renderers, currentGroup, processedRenderers, maxDistance);
|
||
|
||
// 添加组到结果
|
||
groups.Add($"Group_{groupIndex}", currentGroup);
|
||
groupIndex++;
|
||
}
|
||
|
||
Debug.Log($"基于邻近距离分组:将{renderers.Count}个渲染器分成{groups.Count}个组,最大距离为{maxDistance}");
|
||
return groups;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找第一个未处理的渲染器
|
||
/// </summary>
|
||
private static Renderer FindFirstUnprocessedRenderer(List<Renderer> renderers, HashSet<Renderer> processedRenderers)
|
||
{
|
||
foreach (var renderer in renderers)
|
||
{
|
||
if (!processedRenderers.Contains(renderer))
|
||
{
|
||
return renderer;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过邻近距离扩展组
|
||
/// </summary>
|
||
private static void ExpandGroupByProximity(List<Renderer> allRenderers, List<Renderer> currentGroup,
|
||
HashSet<Renderer> processedRenderers, float maxDistance)
|
||
{
|
||
bool addedNew = true;
|
||
while (addedNew)
|
||
{
|
||
addedNew = false;
|
||
|
||
// 查找与当前组中任意一个渲染器距离在阈值内的未处理渲染器
|
||
foreach (var renderer in allRenderers)
|
||
{
|
||
if (processedRenderers.Contains(renderer))
|
||
continue;
|
||
|
||
// 检查是否与组内任何一个渲染器距离小于阈值
|
||
if (IsCloseToAnyInGroup(renderer, currentGroup, maxDistance))
|
||
{
|
||
currentGroup.Add(renderer);
|
||
processedRenderers.Add(renderer);
|
||
addedNew = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查渲染器是否与组内任一渲染器距离小于阈值
|
||
/// </summary>
|
||
private static bool IsCloseToAnyInGroup(Renderer renderer, List<Renderer> group, float maxDistance)
|
||
{
|
||
foreach (var groupRenderer in group)
|
||
{
|
||
float distance = CalculateDistance(renderer, groupRenderer);
|
||
if (distance <= maxDistance)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算两个渲染器之间的距离
|
||
/// </summary>
|
||
private static float CalculateDistance(Renderer renderer1, Renderer renderer2)
|
||
{
|
||
return Vector3.Distance(renderer1.transform.position, renderer2.transform.position);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算渲染组的中心点
|
||
/// </summary>
|
||
public static Vector3 CalculateGroupCenter(List<Renderer> group)
|
||
{
|
||
if (group.Count == 0)
|
||
return Vector3.zero;
|
||
|
||
var sum = Vector3.zero;
|
||
foreach (var renderer in group)
|
||
{
|
||
sum += renderer.transform.position;
|
||
}
|
||
|
||
return sum / group.Count;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据圆形区域对渲染器进行分组(原始算法,保留作参考)
|
||
/// </summary>
|
||
public static Dictionary<string, List<Renderer>> GroupRenderersByCircularDistance(List<Renderer> renderers,
|
||
float maxDistance)
|
||
{
|
||
var groups = new Dictionary<string, List<Renderer>>();
|
||
var groupIndex = 0;
|
||
|
||
// 已分组的渲染器
|
||
var processedRenderers = new HashSet<Renderer>();
|
||
|
||
// 对所有渲染器进行处理
|
||
while (processedRenderers.Count < renderers.Count)
|
||
{
|
||
// 找到第一个未处理的渲染器作为新组的起点
|
||
Renderer startRenderer = FindFirstUnprocessedRenderer(renderers, processedRenderers);
|
||
|
||
if (startRenderer == null)
|
||
break;
|
||
|
||
// 创建新组
|
||
var currentGroup = new List<Renderer>();
|
||
currentGroup.Add(startRenderer);
|
||
processedRenderers.Add(startRenderer);
|
||
|
||
bool addedNew = true;
|
||
while (addedNew)
|
||
{
|
||
addedNew = false;
|
||
|
||
// 计算当前组的中心点
|
||
var groupCenter = CalculateGroupCenter(currentGroup);
|
||
|
||
// 查找距离中心点在阈值内的未处理渲染器
|
||
foreach (var renderer in renderers)
|
||
{
|
||
if (processedRenderers.Contains(renderer))
|
||
continue;
|
||
|
||
var distance = Vector3.Distance(groupCenter, renderer.transform.position);
|
||
if (!(distance <= maxDistance)) continue;
|
||
currentGroup.Add(renderer);
|
||
processedRenderers.Add(renderer);
|
||
addedNew = true;
|
||
}
|
||
}
|
||
|
||
groups.Add($"Group_{groupIndex}", currentGroup);
|
||
groupIndex++;
|
||
}
|
||
|
||
Debug.Log($"基于圆形区域分组:将{renderers.Count}个渲染器分成{groups.Count}个组,半径为{maxDistance}");
|
||
return groups;
|
||
}
|
||
} |