【转】Unity多模型多材质合并,有明显性能提升(FPS)

稍加傻瓜式修正。

原文链接

直接开始:

1.创建一个文件夹 命名为Editor (必须时Editor不能错
在Editor文件夹下创建一个C#脚本命名为:CombinedMeshEditor
脚本内容如下:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

[CustomEditor(typeof(CombinedMesh))]
public class CombinedMeshEditor : Editor
{
    SerializedProperty PropSaveMeshAsset;
    SerializedProperty PropKeepPosition;
    SerializedProperty PropPivotMode;
    SerializedProperty PropMeshObjects;
    SerializedProperty PropRootNode;

    [MenuItem("Tools/Combined Mesh")]
    static void CreateFracturedObject()
    {
        GameObject combinedMeshObject = new GameObject();
        combinedMeshObject.name = "Combined Mesh";
        combinedMeshObject.transform.position = Vector3.zero;
        combinedMeshObject.AddComponent<CombinedMesh>();

        Selection.activeGameObject = combinedMeshObject;
    }
    void Progress(string strMessage, float fT)
    {
        CombinedMesh combinedMesh = serializedObject.targetObject as CombinedMesh;

        Repaint();

        if (EditorUtility.DisplayCancelableProgressBar("Combining", strMessage, fT))
        {
            combinedMesh.CancelCombining();
        }
    }

    void OnEnable()
    {
        PropSaveMeshAsset = serializedObject.FindProperty("SaveMeshAsset");
        PropKeepPosition = serializedObject.FindProperty("KeepPosition");
        PropPivotMode = serializedObject.FindProperty("PivotMode");
        PropMeshObjects = serializedObject.FindProperty("MeshObjects");
        PropRootNode = serializedObject.FindProperty("RootNode");
    }

    public override void OnInspectorGUI()
    {
        int nButtonWidth = 200;

        serializedObject.Update();

        CombinedMesh combinedMesh = serializedObject.targetObject as CombinedMesh;

        EditorGUILayout.Space();
        EditorGUILayout.Space();

        int nNumObjects = combinedMesh.MeshObjects != null ? combinedMesh.MeshObjects.Length : 0;

        EditorGUILayout.PropertyField(PropSaveMeshAsset,
            new GUIContent("Enable Prefab Usage",
                "If activated, will save the mesh to an asset file on disc. Use this if you want to use the generated mesh in prefabs, otherwise prefabs won't reference the mesh correctly."));
        EditorGUILayout.PropertyField(PropKeepPosition,
            new GUIContent("Keep Position",
                "If keep position is activated, the gameobject will keep its current position. Otherwise it will reposition itself to match the objects being combined."));
        EditorGUILayout.PropertyField(PropPivotMode, new GUIContent("Place Pivot Mode", "Where to place the pivot."));
        EditorGUILayout.PropertyField(PropMeshObjects,
            new GUIContent("Source Mesh Objects List (" + nNumObjects + " elements)",
                "The list of objects whose meshes to combine."), true);
        EditorGUILayout.PropertyField(PropRootNode,
            new GUIContent("Root node",
                "Specify an object to set it and its whole hierarchy to the list of objects to combine."));

        EditorGUILayout.Space();
        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        GUILayout.Label(" ");

        serializedObject.ApplyModifiedProperties();

        if (GUILayout.Button(
            new GUIContent("Build List From Root Node",
                "Will build the Source Mesh Objects List using the given object and all the hierarchy below it."),
            GUILayout.Width(nButtonWidth)))
        {
            if (PropRootNode.objectReferenceValue)
            {
                List<MeshFilter> listMeshFilters = new List<MeshFilter>();
                BuildMeshFilterListRecursive(PropRootNode.objectReferenceValue as GameObject, listMeshFilters);
                combinedMesh.MeshObjects = listMeshFilters.ToArray();
            }
        }

        GUILayout.Label(" ");
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        GUILayout.Label(" ");

        if (GUILayout.Button(new GUIContent("Combine", "Starts the combine process."), GUILayout.Width(nButtonWidth)))
        {
            try
            {
                combinedMesh.Combine(Progress);
            }
            catch (System.Exception e)
            {
                Debug.LogError("Exception Type: " + e.GetType().ToString() + ". Message: " + e.Message.ToString() +
                               ". Stack Trace: " + e.StackTrace.ToString());
            }

            EditorUtility.ClearProgressBar();
            GUIUtility.ExitGUI();
        }

        GUILayout.Label(" ");
        EditorGUILayout.EndHorizontal();
    }

    void BuildMeshFilterListRecursive(GameObject node, List<MeshFilter> listMeshFilters)
    {
        MeshFilter meshFilter = node.GetComponent<MeshFilter>();

        if (meshFilter && node.GetComponent<Renderer>())
        {
            listMeshFilters.Add(meshFilter);
        }

        for (int nChild = 0; nChild < node.transform.childCount; nChild++)
        {
            BuildMeshFilterListRecursive(node.transform.GetChild(nChild).gameObject, listMeshFilters);
        }
    }
}

放在哪里?如图:

然后再新建一个脚本。 

创建一个文件夹 命名为:Scripts (主要用于存放脚本的,命名个人习惯不同,我习惯用这个命名),在Scripts文件夹下创建一个脚本命名为:CombinedMesh
脚本内容如下:

using UnityEngine;
using System;
using System.Collections.Generic;

public class CombinedMesh : MonoBehaviour
{
    public bool SaveMeshAsset = false;
    public bool KeepPosition = true;
    public EPivotMode PivotMode = EPivotMode.Center;
    public MeshFilter[] MeshObjects = null;
    public GameObject RootNode = null;

    public delegate void CombineProgressDelegate(string strMessage, float fT);

#if UNITY_EDITOR
    [SerializeField] private string m_strMeshAssetFileName = "";
#endif

    private bool m_bCancelled = false;

    [Serializable]
    public class ObjectInfo
    {
        public ObjectInfo(Material[] aMaterials, Mesh mesh, Transform transform, Matrix4x4 mtxLocal)
        {
            this.aMaterials = new Material[aMaterials.Length];
            aMaterials.CopyTo(this.aMaterials, 0);
            this.mesh = Instantiate(mesh) as Mesh;

            v3LocalPosition = transform.localPosition;
            qLocalRotation = transform.localRotation;
            v3LocalScale = transform.localScale;

            this.mtxLocal = mtxLocal;
            this.mtxWorld = transform.localToWorldMatrix;

            if (mesh.normals != null)
            {
                av3NormalsWorld = mesh.normals;

                for (int nVertex = 0; nVertex < av3NormalsWorld.Length; nVertex++)
                {
                    av3NormalsWorld[nVertex] = mtxWorld.MultiplyVector(av3NormalsWorld[nVertex]);
                }
            }

            if (mesh.tangents != null)
            {
                av4TangentsWorld = mesh.tangents;

                for (int nVertex = 0; nVertex < av4TangentsWorld.Length; nVertex++)
                {
                    Vector3 v3Tangent = new Vector3(av4TangentsWorld[nVertex].x, av4TangentsWorld[nVertex].y,
                        av4TangentsWorld[nVertex].z);
                    v3Tangent = mtxWorld.MultiplyVector(v3Tangent);
                    av4TangentsWorld[nVertex] =
                        new Vector4(v3Tangent.x, v3Tangent.y, v3Tangent.z, av4TangentsWorld[nVertex].w);
                }
            }
        }

        public Material[] aMaterials;
        public Mesh mesh;
        public Vector3 v3LocalPosition;
        public Quaternion qLocalRotation;
        public Vector3 v3LocalScale;
        public Matrix4x4 mtxLocal;
        public Matrix4x4 mtxWorld;
        public Vector3[] av3NormalsWorld;
        public Vector4[] av4TangentsWorld;
    }

    class MaterialMeshInfo
    {
        public MaterialMeshInfo(Transform transform, Mesh mesh, int nSubMesh)
        {
            this.transform = transform;
            this.mesh = mesh;
            this.nSubMesh = nSubMesh;
        }

        public Transform transform;
        public Mesh mesh;
        public int nSubMesh;
    }

    public enum EPivotMode
    {
        Keep,
        Center,
        BottomCenter,
        TopCenter,
        Min,
        Max
    }

    [SerializeField] private List<ObjectInfo> m_listObjectInfo = new List<ObjectInfo>();

    private Dictionary<Material, List<MaterialMeshInfo>> m_dicMeshEntries =
        new Dictionary<Material, List<MaterialMeshInfo>>();

    public void CancelCombining()
    {
        m_bCancelled = true;
    }

    public bool CombiningCancelled()
    {
        return m_bCancelled;
    }

    public void TransformObjInfoMeshVectorsToLocal(Transform newTransform)
    {
        foreach (ObjectInfo objInfo in m_listObjectInfo)
        {
            if (objInfo.mesh.normals != null && objInfo.av3NormalsWorld != null)
            {
                Vector3[] av3Normals = new Vector3[objInfo.av3NormalsWorld.Length];
                objInfo.av3NormalsWorld.CopyTo(av3Normals, 0);

                for (int nVertex = 0; nVertex < av3Normals.Length; nVertex++)
                {
                    av3Normals[nVertex] = newTransform.InverseTransformDirection(av3Normals[nVertex]);
                }

                objInfo.mesh.normals = av3Normals;
            }

            if (objInfo.mesh.tangents != null)
            {
                Vector4[] av4Tangents = new Vector4[objInfo.av4TangentsWorld.Length];
                objInfo.av4TangentsWorld.CopyTo(av4Tangents, 0);

                for (int nVertex = 0; nVertex < av4Tangents.Length; nVertex++)
                {
                    Vector3 v3Tangent = new Vector3(av4Tangents[nVertex].x, av4Tangents[nVertex].y,
                        av4Tangents[nVertex].z);
                    v3Tangent = newTransform.InverseTransformDirection(v3Tangent);
                    av4Tangents[nVertex] = new Vector4(v3Tangent.x, v3Tangent.y, v3Tangent.z, av4Tangents[nVertex].w);
                }

                objInfo.mesh.tangents = av4Tangents;
            }
        }
    }

    public int GetObjectCount()
    {
        return m_listObjectInfo.Count;
    }

    public ObjectInfo GetObjectInfo(int nIndex)
    {
        return m_listObjectInfo[nIndex];
    }

    public void Combine(CombineProgressDelegate progress)
    {
        m_listObjectInfo.Clear();
        m_dicMeshEntries.Clear();
        m_bCancelled = false;

#if UNITY_EDITOR

        if (SaveMeshAsset)
        {
            if (m_strMeshAssetFileName.Length == 0 || System.IO.File.Exists(m_strMeshAssetFileName) == false)
            {
                m_strMeshAssetFileName = UnityEditor.EditorUtility.SaveFilePanelInProject("Save mesh asset",
                    "mesh_" + this.name + this.GetInstanceID().ToString() + ".asset", "asset",
                    "Please enter a file name to save the mesh asset to");
            }
        }

#endif


        bool bUseNormals = false;
        bool bUseTangents = false;
        bool bUseColors = false;
        bool bUseMapping1 = false;
        bool bUseMapping2 = false;

        Vector3 v3Min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        Vector3 v3Max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

        int nMeshFilter = 0;

        foreach (MeshFilter meshFilter in MeshObjects)
        {
            if (progress != null)
            {
                progress("Preprocessing object " + meshFilter.name + "...",
                    (float)nMeshFilter / (float)MeshObjects.Length);
            }

            if (m_bCancelled)
            {
                return;
            }

            if (meshFilter == null)
            {
                continue;
            }

            if (meshFilter.GetComponent<Renderer>() == null)
            {
                Debug.LogWarning(meshFilter.name + " has no mesh renderer available");
                continue;
            }

            Mesh mesh = meshFilter.sharedMesh;

            Vector3[] aVertices = mesh.vertices;

            for (int v = 0; v < aVertices.Length; v++)
            {
                Vector3 v3Pos = meshFilter.transform.TransformPoint(aVertices[v]);

                if (v3Pos.x < v3Min.x) v3Min.x = v3Pos.x;
                if (v3Pos.y < v3Min.y) v3Min.y = v3Pos.y;
                if (v3Pos.z < v3Min.z) v3Min.z = v3Pos.z;
                if (v3Pos.x > v3Max.x) v3Max.x = v3Pos.x;
                if (v3Pos.y > v3Max.y) v3Max.y = v3Pos.y;
                if (v3Pos.z > v3Max.z) v3Max.z = v3Pos.z;
            }

            if (mesh.normals != null)
                if (mesh.normals.Length > 0)
                    bUseNormals = true;
            if (mesh.tangents != null)
                if (mesh.tangents.Length > 0)
                    bUseTangents = true;
            if (mesh.colors != null)
                if (mesh.colors.Length > 0)
                    bUseColors = true;
            if (mesh.colors32 != null)
                if (mesh.colors32.Length > 0)
                    bUseColors = true;
            if (mesh.uv != null)
                if (mesh.uv.Length > 0)
                    bUseMapping1 = true;
            if (mesh.uv2 != null)
                if (mesh.uv2.Length > 0)
                    bUseMapping2 = true;

            for (int nSubMesh = 0; nSubMesh < mesh.subMeshCount; nSubMesh++)
            {
                MaterialMeshInfo newMaterialMeshInfo = new MaterialMeshInfo(meshFilter.transform, mesh, nSubMesh);
                Material material = meshFilter.GetComponent<Renderer>().sharedMaterials[nSubMesh];

                if (m_dicMeshEntries.ContainsKey(material) == false)
                {
                    m_dicMeshEntries.Add(material, new List<MaterialMeshInfo>());
                }

                m_dicMeshEntries[material].Add(newMaterialMeshInfo);
            }

            m_listObjectInfo.Add(new ObjectInfo(meshFilter.GetComponent<Renderer>().sharedMaterials, mesh,
                meshFilter.transform, meshFilter.transform.localToWorldMatrix));
        }

        if (m_dicMeshEntries.Count > 0)
        {

            Vector3 v3Position = transform.position;

            switch (PivotMode)
            {
                case EPivotMode.Keep:
                    v3Position = transform.position;
                    break;
                case EPivotMode.Center:
                    v3Position = (v3Max + v3Min) * 0.5f;
                    break;
                case EPivotMode.BottomCenter:
                    v3Position = (v3Max + v3Min) * 0.5f;
                    v3Position.y = v3Min.y;
                    break;
                case EPivotMode.TopCenter:
                    v3Position = (v3Max + v3Min) * 0.5f;
                    v3Position.y = v3Max.y;
                    break;
                case EPivotMode.Min:
                    v3Position = v3Min;
                    break;
                case EPivotMode.Max:
                    v3Position = v3Max;
                    break;
            }

            Vector3 v3OriginalPosition = transform.position;
            Quaternion qOriginalRotation = transform.rotation;
            Vector3 v3OriginalScale = transform.localScale;

            transform.position = v3Position;
            transform.rotation = Quaternion.identity;
            transform.localScale = Vector3.one;

            Matrix4x4 mtxWorldToNewLocal = this.transform.worldToLocalMatrix;

            if (KeepPosition)
            {
                transform.position = v3OriginalPosition;
                transform.rotation = qOriginalRotation;
                transform.localScale = v3OriginalScale;
            }

            Material[] aMaterials = new Material[m_dicMeshEntries.Keys.Count];
            m_dicMeshEntries.Keys.CopyTo(aMaterials, 0);


            foreach (ObjectInfo objInfo in m_listObjectInfo)
            {
                objInfo.mtxLocal = mtxWorldToNewLocal * objInfo.mtxLocal;
            }


            List<int>[] aListIndices = new List<int>[m_dicMeshEntries.Count];

            List<Vector3> listVertices = new List<Vector3>();
            List<Vector3> listNormals = new List<Vector3>();
            List<Vector4> listTangents = new List<Vector4>();
            List<Color32> listColors = new List<Color32>();
            List<Vector2> listMapping1 = new List<Vector2>();
            List<Vector2> listMapping2 = new List<Vector2>();

            Dictionary<GameObject, int> dicObject2IndexStart = new Dictionary<GameObject, int>();

            int nMaterial = 0;

            foreach (List<MaterialMeshInfo> listMaterialMeshInfo in m_dicMeshEntries.Values)
            {

                aListIndices[nMaterial] = new List<int>();

                int nMaterialMeshInfoIndex = 0;

                foreach (MaterialMeshInfo materialMeshInfo in listMaterialMeshInfo)
                {
                    if (progress != null)
                    {
                        progress("Combining submesh for material " + aMaterials[nMaterial].name + "...",
                            (float)nMaterialMeshInfoIndex / (float)listMaterialMeshInfo.Count);
                    }

                    if (m_bCancelled)
                    {
                        return;
                    }

                    int nIndexStart = listVertices.Count;

                    if (dicObject2IndexStart.ContainsKey(materialMeshInfo.transform.gameObject))
                    {
                        nIndexStart = dicObject2IndexStart[materialMeshInfo.transform.gameObject];
                    }
                    else
                    {
                        Matrix4x4 mtxLocalToWorld = materialMeshInfo.transform.localToWorldMatrix;
                        Matrix4x4 mtxCombined = mtxWorldToNewLocal * mtxLocalToWorld;

                        dicObject2IndexStart.Add(materialMeshInfo.transform.gameObject, nIndexStart);

                        int nVertexCount = materialMeshInfo.mesh.vertexCount;

                        Vector3[] aVertices = materialMeshInfo.mesh.vertices;

                        for (int nVertex = 0; nVertex < aVertices.Length; nVertex++)
                        {
                            aVertices[nVertex] = mtxCombined.MultiplyPoint3x4(aVertices[nVertex]);
                        }

                        listVertices.AddRange(aVertices);

                        if (bUseNormals)
                        {
                            bool bCreateNormals = true;
                            if (materialMeshInfo.mesh.normals != null)
                                if (materialMeshInfo.mesh.normals.Length > 0)
                                    bCreateNormals = false;

                            if (bCreateNormals)
                            {
                                Debug.LogWarning(string.Format(
                                    "Object {0} has mesh with no vertex normals, and some other objects have them. Dummy normals have been added",
                                    materialMeshInfo.transform.name));
                            }

                            Vector3[] av3Normals =
                                bCreateNormals ? new Vector3[nVertexCount] : materialMeshInfo.mesh.normals;

                            for (int nVertex = 0; nVertex < av3Normals.Length; nVertex++)
                            {
                                av3Normals[nVertex] =
                                    materialMeshInfo.transform.TransformDirection(av3Normals[nVertex]);
                                av3Normals[nVertex] = this.transform.InverseTransformDirection(av3Normals[nVertex]);
                            }

                            listNormals.AddRange(av3Normals);
                        }

                        if (bUseTangents)
                        {
                            bool bCreateTangents = true;
                            if (materialMeshInfo.mesh.tangents != null)
                                if (materialMeshInfo.mesh.tangents.Length > 0)
                                    bCreateTangents = false;

                            if (bCreateTangents)
                            {
                                Debug.LogWarning(string.Format(
                                    "Object {0} has mesh with no vertex tangents, and some other objects have them. Dummy tangents have been added",
                                    materialMeshInfo.transform.name));
                            }

                            Vector4[] av4Tangents = bCreateTangents
                                ? new Vector4[nVertexCount]
                                : materialMeshInfo.mesh.tangents;

                            for (int nVertex = 0; nVertex < av4Tangents.Length; nVertex++)
                            {
                                Vector3 v3Tangent = new Vector3(av4Tangents[nVertex].x, av4Tangents[nVertex].y,
                                    av4Tangents[nVertex].z);
                                v3Tangent = materialMeshInfo.transform.TransformDirection(v3Tangent);
                                v3Tangent = transform.InverseTransformDirection(v3Tangent);
                                av4Tangents[nVertex] = new Vector4(v3Tangent.x, v3Tangent.y, v3Tangent.z,
                                    bCreateTangents ? 1.0f : av4Tangents[nVertex].w);
                            }

                            listTangents.AddRange(av4Tangents);
                        }

                        if (bUseColors)
                        {
                            bool bColors = false;
                            bool bColors32 = false;
                            bool bCreateColors = true;

                            if (materialMeshInfo.mesh.colors != null)
                                if (materialMeshInfo.mesh.colors.Length > 0)
                                {
                                    bColors = true;
                                    bCreateColors = false;
                                }

                            if (materialMeshInfo.mesh.colors32 != null)
                                if (materialMeshInfo.mesh.colors32.Length > 0)
                                {
                                    bColors32 = true;
                                    bCreateColors = false;
                                }

                            if (bCreateColors)
                            {
                                Debug.LogWarning(string.Format(
                                    "Object {0} has mesh with no vertex colors, and some other objects have them. Dummy colors have been added",
                                    materialMeshInfo.transform.name));
                            }

                            Color32[] aColors32 = null;

                            if (bCreateColors)
                            {
                                aColors32 = new Color32[nVertexCount];
                            }
                            else if (bColors)
                            {
                                aColors32 = new Color32[nVertexCount];
                                Color[] aColors = materialMeshInfo.mesh.colors;

                                for (int nColor = 0; nColor < nVertexCount; nColor++)
                                {
                                    aColors32[nColor] = aColors[nColor];
                                }
                            }
                            else if (bColors32)
                            {
                                aColors32 = materialMeshInfo.mesh.colors32;
                            }

                            listColors.AddRange(aColors32);
                        }

                        if (bUseMapping1)
                        {
                            bool bCreateMapping1 = true;
                            if (materialMeshInfo.mesh.uv != null)
                                if (materialMeshInfo.mesh.uv.Length > 0)
                                    bCreateMapping1 = false;

                            if (bCreateMapping1)
                            {
                                Debug.LogWarning(string.Format(
                                    "Object {0} has mesh with no vertex mapping (uv), and some other objects have them. Dummy mapping has been added",
                                    materialMeshInfo.transform.name));
                            }

                            Vector2[] av2Mapping1 =
                                bCreateMapping1 ? new Vector2[nVertexCount] : materialMeshInfo.mesh.uv;

                            listMapping1.AddRange(av2Mapping1);
                        }

                        if (bUseMapping2)
                        {
                            bool bCreateMapping2 = true;
                            if (materialMeshInfo.mesh.uv2 != null)
                                if (materialMeshInfo.mesh.uv2.Length > 0)
                                    bCreateMapping2 = false;

                            if (bCreateMapping2)
                            {
                                Debug.LogWarning(string.Format(
                                    "Object {0} has mesh with no vertex mapping (uv2), and some other objects have them. Dummy mapping has been added",
                                    materialMeshInfo.transform.name));
                            }

                            Vector2[] av2Mapping2 =
                                bCreateMapping2 ? new Vector2[nVertexCount] : materialMeshInfo.mesh.uv2;

                            listMapping2.AddRange(av2Mapping2);
                        }
                    }


                    int[] aSubMeshIndices = materialMeshInfo.mesh.GetTriangles(materialMeshInfo.nSubMesh);

                    for (int nIndex = 0; nIndex < aSubMeshIndices.Length; nIndex++)
                    {
                        aListIndices[nMaterial].Add(aSubMeshIndices[nIndex] + nIndexStart);
                    }

                    nMaterialMeshInfoIndex++;
                }

                nMaterial++;
            }


            if (m_bCancelled == false)
            {
                if (progress != null)
                {
                    progress("Building mesh...", 1.0f);
                }


                MeshFilter combinedMeshFilter = gameObject.GetComponent<MeshFilter>();

                if (combinedMeshFilter == null)
                {
                    combinedMeshFilter = gameObject.AddComponent<MeshFilter>();
                }


                if (GetComponent<Renderer>() == null)
                {
                    gameObject.AddComponent<MeshRenderer>();
                }

                GetComponent<Renderer>().sharedMaterials = aMaterials;


                int nVertexLimit = 65000;
                bool useInt32 = false;

                if (listVertices.Count > nVertexLimit)
                {
                    useInt32 = true;
                }

                Mesh newMesh = new Mesh();

                if (useInt32)
                {
                    newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                }

                newMesh.vertices = listVertices.ToArray();
                if (bUseNormals) newMesh.normals = listNormals.ToArray();
                if (bUseTangents) newMesh.tangents = listTangents.ToArray();
                if (bUseColors) newMesh.colors32 = listColors.ToArray();
                if (bUseMapping1) newMesh.uv = listMapping1.ToArray();
                if (bUseMapping2) newMesh.uv2 = listMapping2.ToArray();

                newMesh.subMeshCount = aListIndices.Length;

                for (int nSubMesh = 0; nSubMesh < aListIndices.Length; nSubMesh++)
                {
                    newMesh.SetTriangles(aListIndices[nSubMesh].ToArray(), nSubMesh);
                }

                combinedMeshFilter.sharedMesh = newMesh;

#if UNITY_EDITOR


                if (SaveMeshAsset && m_strMeshAssetFileName.Length > 0)
                {
                    UnityEditor.AssetDatabase.CreateAsset(newMesh, m_strMeshAssetFileName);
                    UnityEditor.AssetDatabase.Refresh();
                }
#endif
            }
        }
        else
        {
            Debug.LogWarning("No meshes were combined because none were found.");
        }
    }
}

这个脚本放在哪里?如图:

加完这两个脚本之后,你会发现菜单栏多了一个菜单(我改成中文了)。如图:

 

 点击CombinedMesh按钮,可以创建一个带有CombinedMesh组件的空对象,如下图:

把你需要合并的模型,放在一个父级空对象下,然后将模型拖入Root node节点。

先点击Build List From Root Node,然后再点击Combine。

等待合并完成。

你会发现材质以及模型都已经合并了。

此时,这个CombinedMesh对象,就已经成为你的合并完成的对象了。如下图:

原来的对象去掉,换成这个即可。

猜你喜欢

转载自blog.csdn.net/u011723630/article/details/127412497
今日推荐