一个网格合并(weld)小工具

在日常开发中会有需求合并多个Mesh网格,并且它们重合处的顶点也要合并,而并非合并成两个subMesh。

而近期刚好在学习Geomipmap的细分,需要把多个mesh块进行合并,于是写了这个脚本

(简单的情况下用Mesh.CombineMeshes也可以)。

 

见下图,多对象合并前后对比:

 

 

使用时传入多个MeshFilter,会返回对应Mesh,但是没做UV、顶点色这些,需要自己扩展:

namespace Hont
{
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public static class MeshCombinerUtil
    {
        public static Mesh Combine(MeshFilter[] meshFilterArary, float weldDistance = 0.01f)
        {
            const int MESH_VERT_GAP = 10_0000;

            Dictionary<int, int> newTrianglesDict = new Dictionary<int, int>();
            List<int> newTrianglesList = new List<int>();
            List<Vector3> newVerticesList = new List<Vector3>();
            List<KeyValuePair<Vector3, int>> meshSlotList = new List<KeyValuePair<Vector3, int>>();

            int counter = 0;
            for (int i = 0; i < meshFilterArary.Length; i++)
            {
                MeshFilter meshFilter = meshFilterArary[i];
                Mesh mesh = meshFilter.sharedMesh;

                Vector3[] verticesArray = mesh.vertices;
                int[] trianglesArray = mesh.triangles;

                for (int j = 0; j < trianglesArray.Length; j++)
                {
                    int triangleIndex = trianglesArray[j];
                    int triangleIndexContainOffset = triangleIndex + i * MESH_VERT_GAP;
                    Vector3 vertex = verticesArray[triangleIndex];
                    vertex = meshFilter.transform.localToWorldMatrix.MultiplyPoint3x4(vertex);

                    if (!newTrianglesDict.ContainsKey(triangleIndexContainOffset))
                    {
                        KeyValuePair<Vector3, int> slotInfo = new KeyValuePair<Vector3, int>(Vector3.zero, -1);
                        for (int k = 0; k < meshSlotList.Count; k++)
                        {
                            KeyValuePair<Vector3, int> meshSlot = meshSlotList[k];

                            if (Vector3.Distance(meshSlot.Key, vertex) <= weldDistance)
                            {
                                slotInfo = meshSlot;
                                break;
                            }
                        } //检索网格交错列表

                        if (slotInfo.Value > -1) //如果网格交错列表里有
                        {
                            newTrianglesDict.Add(triangleIndexContainOffset, slotInfo.Value);
                        }
                        else //如果网格交错列表里没有
                        {
                            meshSlotList.Add(new KeyValuePair<Vector3, int>(vertex, counter));
                            newTrianglesDict.Add(triangleIndexContainOffset, counter);

                            ++counter;
                            newVerticesList.Add(vertex);
                        }
                    } //如果这个原始三角形索引字典里没有则初始化

                    newTrianglesList.Add(newTrianglesDict[triangleIndexContainOffset]);
                }
            }

            Mesh newMesh = new Mesh();
            newMesh.SetVertices(newVerticesList);
            newMesh.SetTriangles(newTrianglesList, 0);

            return newMesh;
        }
    }
}

 

2022/02/13补充,该脚本提供多个MeshFilter的合并,但并不会将硬边转软边,刚好这几天遇到一个需求要进行这一步操作。补充Mesh硬边转软边脚本,搭配使用:

public static Mesh HardEdgeCombine(Mesh mesh, float weldDistance = 0.01f)
{
    int[] triangles = mesh.triangles;
    Vector3[] vertices = mesh.vertices;

    List<int> newTriangleList = new List<int>(triangles.Length);
    List<int> newVertexTriangleIndexList = new List<int>(vertices.Length);
    List<Vector3> newVertexList = new List<Vector3>(vertices.Length);

    int trianglesCounter = 0;
    for (int i = 0; i < triangles.Length; i++)
    {
        int triangleIndex = triangles[i];
        Vector3 vertex = vertices[triangleIndex];

        int dstTriangleIndex = 0;

        bool combineFlag = false;
        for (int j = 0; j < newVertexList.Count; j++)
        {
            Vector3 compareVertex = newVertexList[j];

            if (Vector3.Distance(vertex, compareVertex) <= weldDistance)
            {
                dstTriangleIndex = newVertexTriangleIndexList[j];

                combineFlag = true;
                break;
            }
        }

        if (!combineFlag)
        {
            dstTriangleIndex = trianglesCounter;
            newTriangleList.Add(dstTriangleIndex);
            newVertexList.Add(vertex);
            newVertexTriangleIndexList.Add(dstTriangleIndex);
            trianglesCounter++;
        }
        else
        {
            newTriangleList.Add(dstTriangleIndex);
        }
    }

    Mesh newMesh = new Mesh();
    newMesh.SetVertices(newVertexList);
    newMesh.SetTriangles(newTriangleList, 0);

    newMesh.RecalculateBounds();
    newMesh.RecalculateNormals();
    newMesh.RecalculateTangents();

    return newMesh;
}
HardEdgeCombine

 

posted @ 2021-03-28 09:02  HONT  阅读(455)  评论(0编辑  收藏  举报