示例#1
0
    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

        // Build dictionary

        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.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.renderer.sharedMaterials[nSubMesh];

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

                m_dicMeshEntries[material].Add(newMaterialMeshInfo);
            }

            // Add object info. Matrix will be later transformed to local.
            m_listObjectInfo.Add(new ObjectInfo(meshFilter.renderer.sharedMaterials, mesh, meshFilter.transform, meshFilter.transform.localToWorldMatrix));
        }

        if (m_dicMeshEntries.Count > 0)
        {
            // Position new

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

            // Transform object information matrices to local

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

            // Build mesh

            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)
            {
                // Each entry in this list shares the same material, so it will generate a new submesh entry

                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;

                    // We'll find or initialize the index start, which is the position in the vertex data where this mesh will start when combined

                    if (dicObject2IndexStart.ContainsKey(materialMeshInfo.transform.gameObject))
                    {
                        nIndexStart = dicObject2IndexStart[materialMeshInfo.transform.gameObject];
                    }
                    else
                    {
                        // Now we need to add the mesh vertex data (we'll transform it to the new object local space

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

                    // Now add the indices

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

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

                    nMaterialMeshInfoIndex++;
                }

                nMaterial++;
            }

            // Build the mesh

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

                // Create meshFilter if necessary

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

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

                // Set material list

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

                renderer.sharedMaterials = aMaterials;

                // Build mesh

                int nVertexLimit = 65000;

                if (listVertices.Count > nVertexLimit)
                {
                    Debug.LogWarning("Warning! vertex count = " + listVertices.Count + ". You may be hitting Unity's vertex count limit (" + nVertexLimit + "). Please try combining less objects.");
                }

                Mesh newMesh = new Mesh();

                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
                // Save them to disc

                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.");
        }
    }
示例#2
0
	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

        // Build dictionary

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

            // Add object info. Matrix will be later transformed to local.
            m_listObjectInfo.Add(new ObjectInfo(meshFilter.GetComponent<Renderer>().sharedMaterials, mesh, meshFilter.transform, meshFilter.transform.localToWorldMatrix));
        }

        if(m_dicMeshEntries.Count > 0)
        {
            // Position new

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

            // Transform object information matrices to local

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

            // Build mesh

            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)
            {
                // Each entry in this list shares the same material, so it will generate a new submesh entry

                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;

                    // We'll find or initialize the index start, which is the position in the vertex data where this mesh will start when combined

                    if(dicObject2IndexStart.ContainsKey(materialMeshInfo.transform.gameObject))
                    {
                        nIndexStart = dicObject2IndexStart[materialMeshInfo.transform.gameObject];
                    }
                    else
                    {
                        // Now we need to add the mesh vertex data (we'll transform it to the new object local space

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

                    // Now add the indices

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

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

                    nMaterialMeshInfoIndex++;
                }

                nMaterial++;
            }

            // Build the mesh

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

                // Create meshFilter if necessary

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

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

                // Set material list

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

                GetComponent<Renderer>().sharedMaterials = aMaterials;

                // Build mesh

                int nVertexLimit = 65000;

                if(listVertices.Count > nVertexLimit)
                {
                    Debug.LogWarning("Warning! vertex count = " + listVertices.Count + ". You may be hitting Unity's vertex count limit (" + nVertexLimit + "). Please try combining less objects.");
                }

                Mesh newMesh = new Mesh();

                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

                // Save them to disc

                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.");
        }
    }