先看效果:
再看代码:
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 verticesfor (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 onesfor (int i = 0; i < originalTriangles.Length; i++){int oldIndex = originalTriangles[i];int newIndex = uniqueVertices[originalVertices[oldIndex]];newTriangles.Add(newIndex);}// Create new optimized meshMesh 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方式渲染,就得到了最终的结果。