先看效果:       

Unity给物体添加网格(Wire)绘制的方法-LMLPHP 

再看代码:

using System.Collections.Generic;
using UnityEngine;

public class WireMesh : MonoBehaviour
{
	[SerializeField]
	Material material;

	void Start()
	{
		Mesh mesh = OptimizeMesh(GetComponent<MeshFilter>().mesh);

		GameObject objWire = new(gameObject.name + "_wire");
		objWire.layer = LayerMask.NameToLayer("Wire");

		Mesh meshWird = new() { vertices = mesh.vertices };
		int[] edges = GetEdges(mesh);

		meshWird.SetIndices(edges, MeshTopology.Lines, 0);
		//-------------------------------------------------------------------------------------------
		MeshFilter meshFilter = objWire.AddComponent<MeshFilter>();
		meshFilter.mesh = meshWird;
		MeshRenderer meshRenderer = objWire.AddComponent<MeshRenderer>();
		meshRenderer.material = material;
		objWire.transform.SetParent(transform);
		objWire.transform.localPosition = Vector3.zero;
		objWire.transform.localRotation = Quaternion.identity;
		objWire.transform.localScale = Vector3.one;

		int[] GetEdges(Mesh mesh)
		{
			var hashEdges = new HashSet<(int, int)>();

			var triangles = mesh.triangles;

			for (int i = 0; i < triangles.Length; i += 3)
			{
				AddEdge(triangles[i], triangles[i + 1]);
				AddEdge(triangles[i + 1], triangles[i + 2]);
				AddEdge(triangles[i + 2], triangles[i]);
			}

			List<int> listTriangle = new();
			foreach (var val in hashEdges)
			{
				listTriangle.Add(val.Item1);
				listTriangle.Add(val.Item2);
			}

			return listTriangle.ToArray();

			void AddEdge(int id1, int id2)
			{
				var edge = (Mathf.Min(id1, id2), Mathf.Max(id1, id2));
				hashEdges.Add(edge); // 只添加唯一组合
			}
		}
	}

	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>();

		// Re-index vertices
		for (int i = 0; i < originalVertices.Length; i++)
		{
			Vector3 vertex = originalVertices[i];

			if (!uniqueVertices.ContainsKey(vertex))
			{
				uniqueVertices[vertex] = newVertices.Count;
				newVertices.Add(vertex);
			}
		}

		// Map old indices to new ones
		for (int i = 0; i < originalTriangles.Length; i++)
		{
			int oldIndex = originalTriangles[i];
			int newIndex = uniqueVertices[originalVertices[oldIndex]];
			newTriangles.Add(newIndex);
		}

		// Create new optimized mesh
		Mesh optimizedMesh = new()
		{
			vertices = newVertices.ToArray(),
			triangles = newTriangles.ToArray()
		};
		//
		if (recalculate)
		{
			optimizedMesh.RecalculateNormals();
			optimizedMesh.RecalculateBounds();
		} 

		return optimizedMesh;
	}
}

        这个代码给一个物体添加一个与原始物体重叠的网格渲染的物体。

        这里面涉及到了一些知识点和操作方法,逐条说一下。

        首先是网格内容优化。这里说的优化只是Mesh记录数据量的优化,并不是说能在渲染速度上的优化。为什么这么说呢?当我们把一个模型文件导入到unity中后,不管原来的网格数据是怎样的,unity总是会让顶点数组中的顶点(Vector3)复制出多个来,假设一个fbx格式的立方体有8个顶点,但Unity在使用时会显示Mesh包含24个顶点,不知道是否是出于提升渲染速度的考虑。但我们要尽可能优化这个点数,这样索引的最大值也会变小,也能让我们渲染的wire的边变少,否则同样的边会重复渲染多次。这里OptimizeMesh方法将Mesh中重复的点去掉,同时也重置了面索引。在GetEdges方法中使用HashSet,这保证了不出现重叠的边。最后我们让Mesh使用了MeshTopology.Lines方式渲染,就得到了最终的结果。

        

09-29 19:28