Unity查找网格边缘并给边缘绘制线条代码参考

效果参考如下:

代码参考如下:

using System.Collections.Generic;
using UnityEngine;

public class BorderFind : MonoBehaviour
{
	[SerializeField]
	MeshFilter meshFilter;
	[SerializeField]
	Material matLine;

	void Start()
	{
		if (meshFilter == null) return;
		Mesh mesh = OptimizeMesh(meshFilter.sharedMesh, true);
		if (mesh == null) return;
		List<List<Vector3>> borders = GetBorders(mesh);
		foreach (List<Vector3> b in borders)
		{
			GameObject go = new GameObject();
			go.transform.parent = transform;
			LineRenderer lineRenderer = go.AddComponent<LineRenderer>();
			lineRenderer.positionCount = b.Count;
			lineRenderer.SetPositions(b.ToArray());
			lineRenderer.loop = true;
			lineRenderer.material = Instantiate(matLine);
			lineRenderer.material.color = Random.ColorHSV();
		}
	}

	List<List<Vector3>> GetBorders(Mesh meshOriginal)
	{
		List<Edge> listEdgeNoSharedAll = new();
		Mesh mesh = OptimizeMesh(meshOriginal, true);
		Vector3[] vs = mesh.vertices;
		int[] ts = mesh.triangles;

		for (int i = 0; i < ts.Length; i += 3)
		{
			int edge01Start = ts[i];
			int edge01End = ts[i + 1];
			int edge02Start = ts[i + 1];
			int edge02End = ts[i + 2];
			int edge03Start = ts[i + 2];
			int edge03End = ts[i];

			bool isEdge01Shared = false;
			bool isEdge02Shared = false;
			bool isEdge03Shared = false;

			for (int j = 0; j < ts.Length; j +=3)
			{
				if (j == i) continue;
				int e01Start = ts[j];
				int e01End = ts[j + 1];
				int e02Start = ts[j + 1];
				int e02End = ts[j + 2];
				int e03Start = ts[j + 2];
				int e03End = ts[j];
				if ((e01Start == edge01Start && e01End == edge01End) || (e01End == edge01Start && e01Start == edge01End))
				{
					isEdge01Shared = true;
					break;
				}
				if ((e02Start == edge01Start && e02End == edge01End) || (e02End == edge01Start && e02Start == edge01End))
				{
					isEdge01Shared = true;
					break;
				}
				if ((e03Start == edge01Start && e03End == edge01End) || (e03End == edge01Start && e03Start == edge01End))
				{
					isEdge01Shared = true;
					break;
				}
			}

			for (int j = 0; j < ts.Length; j += 3)
			{
				if (j == i) continue;
				int e01Start = ts[j];
				int e01End = ts[j + 1];
				int e02Start = ts[j + 1];
				int e02End = ts[j + 2];
				int e03Start = ts[j + 2];
				int e03End = ts[j];
				if ((e01Start == edge02Start && e01End == edge02End) || (e01End == edge02Start && e01Start == edge02End))
				{
					isEdge02Shared = true;
					break;
				}
				if ((e02Start == edge02Start && e02End == edge02End) || (e02End == edge02Start && e02Start == edge02End))
				{
					isEdge02Shared = true;
					break;
				}
				if ((e03Start == edge02Start && e03End == edge02End) || (e03End == edge02Start && e03Start == edge02End))
				{
					isEdge02Shared = true;
					break;
				}
			}

			for (int j = 0; j < ts.Length; j += 3)
			{
				if (j == i) continue;
				int e01Start = ts[j];
				int e01End = ts[j + 1];
				int e02Start = ts[j + 1];
				int e02End = ts[j + 2];
				int e03Start = ts[j + 2];
				int e03End = ts[j];
				if ((e01Start == edge03Start && e01End == edge03End) || (e01End == edge03Start && e01Start == edge03End))
				{
					isEdge03Shared = true;
					break;
				}
				if ((e02Start == edge03Start && e02End == edge03End) || (e02End == edge03Start && e02Start == edge03End))
				{
					isEdge03Shared = true;
					break;
				}
				if ((e03Start == edge03Start && e03End == edge03End) || (e03End == edge03Start && e03Start == edge03End))
				{
					isEdge03Shared = true;
					break;
				}
			}

			if (!isEdge01Shared)
			{
				listEdgeNoSharedAll.Add(new Edge(edge01Start, edge01End));
			}
			if (!isEdge02Shared)
			{
				listEdgeNoSharedAll.Add(new Edge(edge02Start, edge02End));
			}
			if (!isEdge03Shared)
			{
				listEdgeNoSharedAll.Add(new Edge(edge03Start, edge03End));
			}
		}


		List<List<Vector3>> listVerts = new();
		Debug.Log(listEdgeNoSharedAll.Count);
		if (listEdgeNoSharedAll.Count == 0) return listVerts;

		do
		{
			List<Edge> listEdgeNoShared = new();
			Edge edgeFirst = listEdgeNoSharedAll[0];
			Edge curEdge = edgeFirst;
			listEdgeNoSharedAll.RemoveAt(0);
			listEdgeNoShared.Add(edgeFirst);

			bool isClosed = false;
			while (!isClosed || listEdgeNoSharedAll.Count > 0)
			{
				bool hasConnect = false;
				foreach (Edge e in listEdgeNoSharedAll)
				{
					if (curEdge.end == e.start)
					{
						curEdge = e;
						listEdgeNoSharedAll.Remove(e);
						listEdgeNoShared.Add(e);
						if (edgeFirst.start == e.end)
						{
							isClosed = true;
						}
						hasConnect = true;
						break;
					}

					if (curEdge.end == e.end)
					{
						e.Switch();
						curEdge = e;
						listEdgeNoSharedAll.Remove(e);
						listEdgeNoShared.Add(e);
						if (edgeFirst.start == e.end)
						{
							isClosed = true;
						}
						hasConnect = true;
						break;
					}
				}

				if (!hasConnect) break;
			}

			List<Vector3> listVert = new List<Vector3>();
			foreach (Edge e in listEdgeNoShared)
			{
				listVert.Add(vs[e.start]);
			}
			listVerts.Add(listVert);
		} while (listEdgeNoSharedAll.Count > 0);

		return listVerts;
	}

	Mesh OptimizeMesh(Mesh originalMesh, bool recalculate = false)
	{
		Vector3[] originalVertices = originalMesh.vertices;
		int[] originalTriangles = originalMesh.triangles;

		Dictionary<Vector3, int> uniqueVertices = new Dictionary<Vector3, int>();
		List<Vector3> newVertices = new List<Vector3>();
		List<int> newTriangles = new List<int>();
		for (int i = 0; i < originalVertices.Length; i++)
		{
			Vector3 vertex = originalVertices[i];
			if (!uniqueVertices.ContainsKey(vertex))
			{
				uniqueVertices[vertex] = newVertices.Count;
				newVertices.Add(vertex);
			}
		}

		for (int i = 0; i < originalTriangles.Length; i++)
		{
			int oldIndex = originalTriangles[i];
			int newIndex = uniqueVertices[originalVertices[oldIndex]];
			newTriangles.Add(newIndex);
		}

		Mesh optimizedMesh = new()
		{
			vertices = newVertices.ToArray(),
			triangles = newTriangles.ToArray()
		};

		if (recalculate)
		{
			optimizedMesh.RecalculateNormals();
			optimizedMesh.RecalculateBounds();
		}
		return optimizedMesh;
	}

	struct Edge
	{
		public int start;
		public int end;
		public Edge(int start, int end) { this.start = start; this.end = end; }
		public void Switch() { (start, end) = (end, start); }
	}
}

猜你喜欢

转载自blog.csdn.net/ttod/article/details/142895865