259 lines
8.2 KiB
C#
259 lines
8.2 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
[System.Serializable]
|
|||
|
|
public class MarchingSquaresProcessor
|
|||
|
|
{
|
|||
|
|
[Header("Marching Squares设置")]
|
|||
|
|
public float isoLevel = 0.5f;
|
|||
|
|
public bool smoothEdges = true;
|
|||
|
|
public float smoothness = 0.1f;
|
|||
|
|
|
|||
|
|
// Marching Squares查找表
|
|||
|
|
private static readonly int[,] transitionTable = new int[,]
|
|||
|
|
{
|
|||
|
|
{-1, -1, -1, -1}, // 0: 空单元格
|
|||
|
|
{ 0, 3, -1, -1}, // 1: 只有左下角
|
|||
|
|
{ 1, 0, -1, -1}, // 2: 只有右下角
|
|||
|
|
{ 1, 3, -1, -1}, // 3: 下边
|
|||
|
|
{ 2, 1, -1, -1}, // 4: 只有右上角
|
|||
|
|
{ 0, 3, 2, 1}, // 5: S形状
|
|||
|
|
{ 2, 0, -1, -1}, // 6: 右边
|
|||
|
|
{ 2, 3, -1, -1}, // 7: 右下三角
|
|||
|
|
{ 3, 2, -1, -1}, // 8: 只有左上角
|
|||
|
|
{ 0, 2, -1, -1}, // 9: 左边
|
|||
|
|
{ 0, 1, 3, 2}, // 10: S形状(反转)
|
|||
|
|
{ 1, 2, -1, -1}, // 11: 左下三角
|
|||
|
|
{ 3, 1, -1, -1}, // 12: 上边
|
|||
|
|
{ 3, 0, -1, -1}, // 13: 右上三角
|
|||
|
|
{ 1, 3, -1, -1}, // 14: 左上三角
|
|||
|
|
{-1, -1, -1, -1} // 15: 全满
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
public List<List<Vector2>> ExtractContours(DensityGrid grid)
|
|||
|
|
{
|
|||
|
|
var contours = new List<List<Vector2>>();
|
|||
|
|
bool[,] visited = new bool[grid.Width, grid.Height];
|
|||
|
|
|
|||
|
|
for (int x = 0; x < grid.Width - 1; x++)
|
|||
|
|
{
|
|||
|
|
for (int y = 0; y < grid.Height - 1; y++)
|
|||
|
|
{
|
|||
|
|
if (!visited[x, y] && IsBoundaryCell(grid, x, y))
|
|||
|
|
{
|
|||
|
|
var contour = MarchCell(grid, x, y, visited);
|
|||
|
|
if (contour != null && contour.Count >= 3)
|
|||
|
|
{
|
|||
|
|
if (smoothEdges)
|
|||
|
|
contour = SmoothContour(contour);
|
|||
|
|
contours.Add(contour);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return contours;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
List<Vector2> MarchCell(DensityGrid grid, int startX, int startY, bool[,] visited)
|
|||
|
|
{
|
|||
|
|
var contour = new List<Vector2>();
|
|||
|
|
int x = startX, y = startY;
|
|||
|
|
int step = 0;
|
|||
|
|
int maxSteps = grid.Width * grid.Height; // 防止无限循环
|
|||
|
|
|
|||
|
|
do
|
|||
|
|
{
|
|||
|
|
// 边界检查
|
|||
|
|
if (x < 0 || x >= grid.Width - 1 || y < 0 || y >= grid.Height - 1)
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
if (visited[x, y])
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
visited[x, y] = true;
|
|||
|
|
|
|||
|
|
int config = GetCellConfiguration(grid, x, y);
|
|||
|
|
var edgePoints = GetEdgePoints(grid, x, y, config);
|
|||
|
|
|
|||
|
|
// 只添加有效的点
|
|||
|
|
foreach (var point in edgePoints)
|
|||
|
|
{
|
|||
|
|
if (!contour.Contains(point)) // 简单的去重
|
|||
|
|
contour.Add(point);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 移动到下一个单元格
|
|||
|
|
if (!MoveToNextCell(config, ref x, ref y))
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
step++;
|
|||
|
|
|
|||
|
|
} while ((x != startX || y != startY) && step < maxSteps);
|
|||
|
|
|
|||
|
|
return contour;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int GetCellConfiguration(DensityGrid grid, int x, int y)
|
|||
|
|
{
|
|||
|
|
int config = 0;
|
|||
|
|
|
|||
|
|
// 安全地获取值,处理边界情况
|
|||
|
|
float a = GetSafeValue(grid, x, y);
|
|||
|
|
float b = GetSafeValue(grid, x + 1, y);
|
|||
|
|
float c = GetSafeValue(grid, x + 1, y + 1);
|
|||
|
|
float d = GetSafeValue(grid, x, y + 1);
|
|||
|
|
|
|||
|
|
if (a >= isoLevel) config |= 1;
|
|||
|
|
if (b >= isoLevel) config |= 2;
|
|||
|
|
if (c >= isoLevel) config |= 4;
|
|||
|
|
if (d >= isoLevel) config |= 8;
|
|||
|
|
|
|||
|
|
return config;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float GetSafeValue(DensityGrid grid, int x, int y)
|
|||
|
|
{
|
|||
|
|
if (x < 0 || x >= grid.Width || y < 0 || y >= grid.Height)
|
|||
|
|
return 0f;
|
|||
|
|
return grid.GetValue(x, y);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector2[] GetEdgePoints(DensityGrid grid, int x, int y, int config)
|
|||
|
|
{
|
|||
|
|
var points = new List<Vector2>();
|
|||
|
|
|
|||
|
|
// 根据配置添加边点
|
|||
|
|
switch (config)
|
|||
|
|
{
|
|||
|
|
case 1:
|
|||
|
|
case 14:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边
|
|||
|
|
break;
|
|||
|
|
case 2:
|
|||
|
|
case 13:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边
|
|||
|
|
points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边
|
|||
|
|
break;
|
|||
|
|
case 3:
|
|||
|
|
case 12:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边
|
|||
|
|
points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边
|
|||
|
|
break;
|
|||
|
|
case 4:
|
|||
|
|
case 11:
|
|||
|
|
points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边
|
|||
|
|
break;
|
|||
|
|
case 5:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边
|
|||
|
|
points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边
|
|||
|
|
break;
|
|||
|
|
case 6:
|
|||
|
|
case 9:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边
|
|||
|
|
break;
|
|||
|
|
case 7:
|
|||
|
|
case 8:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边
|
|||
|
|
break;
|
|||
|
|
case 10:
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x, y + 1)); // 左边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y, x + 1, y)); // 底边
|
|||
|
|
points.Add(InterpolateEdge(grid, x + 1, y, x + 1, y + 1)); // 右边
|
|||
|
|
points.Add(InterpolateEdge(grid, x, y + 1, x + 1, y + 1)); // 顶边
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return points.ToArray();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector2 InterpolateEdge(DensityGrid grid, int x1, int y1, int x2, int y2)
|
|||
|
|
{
|
|||
|
|
// 安全获取值
|
|||
|
|
float v1 = GetSafeValue(grid, x1, y1);
|
|||
|
|
float v2 = GetSafeValue(grid, x2, y2);
|
|||
|
|
|
|||
|
|
if (Mathf.Abs(v1 - v2) < 0.001f)
|
|||
|
|
return grid.GridToLocalPosition(x1, y1);
|
|||
|
|
|
|||
|
|
float t = (isoLevel - v1) / (v2 - v1);
|
|||
|
|
t = Mathf.Clamp01(t);
|
|||
|
|
|
|||
|
|
Vector2 p1 = grid.GridToLocalPosition(x1, y1);
|
|||
|
|
Vector2 p2 = grid.GridToLocalPosition(x2, y2);
|
|||
|
|
|
|||
|
|
return Vector2.Lerp(p1, p2, t);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool MoveToNextCell(int config, ref int x, ref int y)
|
|||
|
|
{
|
|||
|
|
// 简化的移动逻辑 - 根据配置决定下一个单元格
|
|||
|
|
switch (config)
|
|||
|
|
{
|
|||
|
|
case 1:
|
|||
|
|
case 3:
|
|||
|
|
case 7:
|
|||
|
|
case 5:
|
|||
|
|
y++; break; // 向上移动
|
|||
|
|
case 2:
|
|||
|
|
case 6:
|
|||
|
|
case 10:
|
|||
|
|
case 14:
|
|||
|
|
x++; break; // 向右移动
|
|||
|
|
case 4:
|
|||
|
|
case 12:
|
|||
|
|
case 13:
|
|||
|
|
case 15:
|
|||
|
|
y--; break; // 向下移动
|
|||
|
|
case 8:
|
|||
|
|
case 9:
|
|||
|
|
case 11:
|
|||
|
|
x--; break; // 向左移动
|
|||
|
|
default:
|
|||
|
|
return false; // 无法移动
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
List<Vector2> SmoothContour(List<Vector2> contour)
|
|||
|
|
{
|
|||
|
|
if (contour.Count < 4) return contour;
|
|||
|
|
|
|||
|
|
var smoothed = new List<Vector2>();
|
|||
|
|
for (int i = 0; i < contour.Count; i++)
|
|||
|
|
{
|
|||
|
|
Vector2 prev = contour[(i - 1 + contour.Count) % contour.Count];
|
|||
|
|
Vector2 current = contour[i];
|
|||
|
|
Vector2 next = contour[(i + 1) % contour.Count];
|
|||
|
|
|
|||
|
|
Vector2 smoothedPoint = (prev + current * 2f + next) / 4f;
|
|||
|
|
smoothed.Add(smoothedPoint);
|
|||
|
|
}
|
|||
|
|
return smoothed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool IsBoundaryCell(DensityGrid grid, int x, int y)
|
|||
|
|
{
|
|||
|
|
// 安全检查
|
|||
|
|
if (x < 0 || x >= grid.Width - 1 || y < 0 || y >= grid.Height - 1)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
float value = grid.GetValue(x, y);
|
|||
|
|
return value >= isoLevel && value < 1.0f; // 边界单元格
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void DrawGridGizmos(Transform wall)
|
|||
|
|
{
|
|||
|
|
// 调试可视化代码可以留空或简化
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
// 可选:添加网格可视化
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
}
|