合并子网格/多材质球

版权声明:join share https://blog.csdn.net/qq_16072507/article/details/78541270
1、对于网格贴图坐标在【0,1】范围内的游戏物体,可以合并贴图。
2、对应网格贴图坐标超出【0,1】范围的游戏物体,合并网格,不合并贴图,需要编写定制纹理数的shader。
          如果也用合并贴图的方式,会在贴图重复使用的接缝处出现斑马线
          (需要在片元着色器将uv转换到【0,1】范围(uv= uv-floor(uv);这个操作会导致斑马线),再用rect转换到合并后的贴图)。


方案2:对应网格贴图坐标超出【0,1】范围的游戏物体,合并网格,不合并贴图,需要编写定制纹理数的shader。
               如果也用合并贴图的方式,会在贴图重复使用的接缝处出现斑马线
               (需要在片元着色器将uv转换到【0,1】范围(uv= uv-floor(uv);这个操作会导致斑马线),再用rect转换到合并后的贴图)。
                    斑马线效果:
               
1、合并网格




2、添加网格渲染器,编辑定制贴图数量的shader,创建材质球,指定多个对应贴图。


代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class CombineSubMeshToPrefab : MonoBehaviour {
    [MenuItem("Tools/Combine SubMesh And Create Prefab & C")]
    public static void CombineSubMesh()  
    {
        GameObject go = Selection.activeGameObject;
        if (go)
        {
            MeshFilter mf = go.GetComponent<MeshFilter>();
            if (mf)
            {
                Mesh mesh = mf.sharedMesh;
                if (mesh)
                {
                    Mesh cMesh = MeshUtil.MergeSubMesh(mesh);
                    if (cMesh)
                    {
                        string meshPath = "Assets/__source/Model/Combined/"+cMesh.name+".asset";
                        AssetDatabase.DeleteAsset(meshPath);
                        AssetDatabase.CreateAsset(cMesh, meshPath);
                        GameObject cGo = new GameObject("CSM_" + go.name);
                        cGo.transform.parent = go.transform;
                        MeshFilter cMf=cGo.AddComponent<MeshFilter>();
                        cMf.sharedMesh = cMesh;
                        string prefabPath = "Assets/__source/Prefab/Combined/"+ cGo.name+".prefab";
                        Object tempPrefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
                        tempPrefab = PrefabUtility.ReplacePrefab(cGo, tempPrefab);
                    }
                }
            }
        }
    }
   
}


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class MeshUtil{
    [MenuItem("Tools/Combine SubMesh & M")]
    public static void CombineSubMesh()
    {
        GameObject go = Selection.activeGameObject;
        if (go)
        {
            MeshFilter mf = go.GetComponent<MeshFilter>();
            if (mf)
            {
                Mesh mesh = mf.sharedMesh;
                if (mesh)
                {
                    Mesh cMesh = MeshUtil.MergeSubMesh(mesh);
                    if (cMesh)
                    {
                        string meshPath = "Assets/__source/Model/Combined/" + cMesh.name + ".asset";
                        AssetDatabase.DeleteAsset(meshPath);
                        AssetDatabase.CreateAsset(cMesh, meshPath);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 深度复制网格
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public static Mesh MeshTrueCopy(Mesh i)
    {
        Mesh o = new Mesh();

        o.name = i.name;
        o.hideFlags = i.hideFlags;
        //顶点 位置 方向
        o.vertices = i.vertices;
        o.normals = i.normals;
        o.tangents = i.tangents;
        //三角面
        o.triangles = i.triangles;
        o.subMeshCount = i.subMeshCount;
        //颜色
        o.uv = i.uv;
        int dCount = 50;
        for(int j=0;j<o.vertexCount;j++)
        {
            if (dCount > 0&&(Mathf.Abs(o.uv[j].x)>1|| Mathf.Abs(o.uv[j].y) > 1))
            {
                dCount--;
                Debug.Log("uv=" + o.uv[j].x+" "+o.uv[j].y);
            }
            if (dCount == 0)
            {
                break;
            }
        }

        o.uv2 = i.uv2;
        o.uv3 = i.uv3;
        o.uv4 = i.uv4;
        o.colors = i.colors;
        o.colors32 = i.colors32;
        //边缘
        o.bounds = i.bounds;
        //骨骼
        o.boneWeights = i.boneWeights;
        o.bindposes = i.bindposes;
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// 同时更新UV
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh,Rect[] texRects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);

        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();
                CopyAndAddVertexs(hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            Debug.Log("更新UV前此子网格各顶点的UV值【"+ ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            UpdateUv(newSubmeshTrianges, texRects[i],ref tarUVList);
            Debug.Log("Rect【"+texRects[i].ToString()+"】更新UV后此子网格各顶点的UV值【" + ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static string ShowUVsi(int[] newSubmeshTriange, List<Vector2> tarUVList)
    {
        string rs = "[";
        foreach (int idx in newSubmeshTriange)
        {
            rs+= idx+":(" +tarUVList[idx].x+","+ tarUVList[idx].y+")|";
        }
        return rs+"]";
    }
    public static void UpdateUv(int[] newSubmeshTrianges,Rect texRect,ref List<Vector2> tarUVList)
    {
        List<int> vertexIndexs_noRepeat = ArrayRemoveDuplication(newSubmeshTrianges);
        foreach (int idx in vertexIndexs_noRepeat)
        {
            float x = texRect.x + UVToZeroOne(tarUVList[idx].x) * texRect.width;
            float y = texRect.y + UVToZeroOne(tarUVList[idx].y) * texRect.height;
            if (idx == 0)
            {
                Debug.Log("idx="+idx+"  x="+x+"  old x="+ tarUVList[idx].x+ "  UVToZeroOne=" + UVToZeroOne(tarUVList[idx].x) + " texRect="+texRect.ToString());
            }
            tarUVList[idx] = new Vector2(x,y);
        }
    }
    public static float UVToZeroOne(float i)
    {
        float o = 0;
        o = i - Mathf.Floor(i);
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【"+i+"】拥有三角形数量为【"+(srcSubmeshTriangeArray.Length/3)+"】顶点索引为【"+ ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【"+ ShowArrayElements(hadSharedVertexIndexArr) +"】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【"+ tarVertexList.Count+ "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i,hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList,ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【"+ ShowDictionary(vertexIndexRef)+ "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【"+ ShowArrayElements(newSubmeshTrianges)+ "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【"+i+"】循环结束,未更新三角形顶点索引为【"+ShowListElements(srcBeforCurrentSubmeshTrianges)+"】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_"+srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMeshStoreRect(Mesh srcMesh,Rect[] rects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<Vector2> tarUV3List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        tarUV3List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i, hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            //UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            StoreRectToUV(newSubmeshTrianges, rects[i], ref tarUV2List, ref tarUV3List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.uv3 = tarUV3List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static void StoreRectToUV(int[] newSubmeshTrianges,Rect rect,ref List<Vector2> uv2,ref List<Vector2> uv3)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2(rect.x, rect.y);
                uv3[vIdx] = new Vector2(rect.width, rect.height);
            }
        }
    }
    public static void UdateUv2(int currSubmeshId, int[] newSubmeshTrianges, ref List<Vector2> uv2)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2((float)currSubmeshId,0.0f);
            }
        }
        //Debug.Log("UV2="+ ShowUVs(uv2));
    }
    public static string ShowUVs(List<Vector2> uv2)
    {
        string rs = "";
        for(int i=0;i<uv2.Count; i++)
        {
            rs += i+"["+uv2[i].x+","+uv2[i].y+"] ";
        }
        return rs;
    }
    public static int[] UpdateTrianges(int[] oldTrianges,Dictionary<int,int> idxRef)
    {
        int[] newTrianges = new int[oldTrianges.Length];
        for (int i = 0; i < oldTrianges.Length; i++)
        {
            if (idxRef.ContainsKey(oldTrianges[i]))
            {
                newTrianges[i] = idxRef[oldTrianges[i]];
            }
            else
            {
                newTrianges[i] = oldTrianges[i];
            }
        }
        return newTrianges;
    }
    public static int[] CopyArray(int[] arr)
    {
        int[] o = new int[arr.Length];
        for (int i = 0; i < arr.Length; i++)
        {
            o[i] = arr[i];
        }
        return o;
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// </summary>
    /// <param name="vIndexArr"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int[] vIndexArr, Vector2[] srcUVList,
                                        ref List<Vector3> oldVextexList,
                                        ref List<Vector3> oldNormalList,
                                        ref List<Vector2> oldUVList,
                                        ref Dictionary<int,int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref List<Vector2> oldUV3List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh, 0.0f));
                oldUV3List.Add(new Vector2((float)currentSubmesh, 0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh,0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 初始化顶点或法线列表
    /// </summary>
    /// <param name="srcVertexArray"></param>
    /// <returns></returns>
    public static List<Vector3> initVertexOrNormalList(Vector3[] srcVertexArray)
    {
        List<Vector3> vList = new List<Vector3>();
        if (!(srcVertexArray == null || srcVertexArray.Length == 0))
        {
            foreach (Vector3 e in srcVertexArray)
            {
                vList.Add(e);
            }
        }
        return vList;
    }
    /// <summary>
    /// 初始化UV列表
    /// </summary>
    /// <param name="srcUvArray"></param>
    /// <returns></returns>
    public static List<Vector2> initUvList(Vector2[] srcUvArray)
    {
        List<Vector2> uvList = new List<Vector2>();
        if (!(srcUvArray == null || srcUvArray.Length == 0))
        {
            foreach (Vector2 e in srcUvArray)
            {
                uvList.Add(e);
            }
        }
        return uvList;
    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] MergeArrayToArray(int[] arr1,int[] arr2)
    {
        if (arr1 == null || arr1.Length == 0)
        {
            return arr2;
        }
        else if (arr2 == null || arr2.Length == 0)
        {
            return arr1;
        }
        else
        {
            int[] mergeArr =new int[arr1.Length + arr2.Length];
            for (int i = 0; i < arr1.Length; i++)
            {
                mergeArr[i] = arr1[i];
            }
            for (int i = 0; i < arr2.Length; i++)
            {
                mergeArr[arr1.Length+i] = arr2[i];
            }
            return mergeArr;
        }

    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static List<int> MergeArrayToList(int[] arr1, int[] arr2)
    {
        int[] arr = MergeArrayToArray(arr1,arr2);
        List<int> list = new List<int>();
        if (!(arr == null || arr.Length == 0))
        {
            foreach (int e in arr)
            {
                list.Add(e);
            }
        }
        return list;
    }
    /// <summary>
    /// 去除数组中的重复元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static List<int> ArrayRemoveDuplication(int [] arr)
    {
        List<int> list = new List<int>();
        foreach (int i in arr)
        {
            if (!list.Contains(i))
            {
                list.Add(i);
            }
        }
        return list;
    }
    /// <summary>
    /// 找出数组2在数组1中已包含的元素
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] ArrayFindSharedElements(int[] arr1, int[] arr2)
    {
        List<int> list1_noRepeat = ArrayRemoveDuplication(arr1);
        List<int> list2_noRepeat = ArrayRemoveDuplication(arr2);
        List<int> comm = new List<int>();
        foreach (int e in list2_noRepeat)
        {
            if (list1_noRepeat.Contains(e))
            {
                comm.Add(e);
            }
        }
        return comm.ToArray();
    }
    /// <summary>
    /// 显示数组元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static string ShowArrayElements(int[] arr)
    {
        string rs = "[";
        foreach(int i in arr)
        {
            rs += i + " ";
        }
        return rs+"]";
    }
    public static string ShowListElements(List<int> list)
    {
        return ShowArrayElements(list.ToArray());
    }
    public static string ShowDictionary(Dictionary<int,int> dic)
    {
        string rs = "";
        foreach (int k in dic.Keys)
        {
            rs += k + "-->" + dic[k] + "|";
        }
        return rs;
    }
}


Shader "6/Room_Ruin_2_Opaque_Texs"
{
       Properties
       {
              
       _MainTex("Abedo", 2D) = "white" {}
       _MainTex_1("Abedo 1", 2D) = "white" {}
       _MainTex_2("Abedo 2", 2D) = "white" {}
       _MainTex_3("Abedo 3", 2D) = "white" {}
       _MainTex_4("Abedo 4", 2D) = "white" {}
       _MainTex_5("Abedo 5", 2D) = "white" {}
       _MainTex_6("Abedo 6", 2D) = "white" {}
       _MainTex_7("Abedo 7", 2D) = "white" {}
       _Color("Abedo Color",Color) = (1,1,1,1)
              //_AlphaTex("Alpha",2D) = ""{}
              //_AlphaScale("Alpha Scale",Range(0.0,1.0))=1.0
              _NormalTex("Normal",2D) = "bump"{}
       _BumpScale("Normal/Bump Scale",Range(0.0,3.0)) = 1.0
              [Header(specular)]
       _Specular("Specular",Color) = (1,1,1,1)
              _Gloss("Gloss",Range(8,256)) = 20
              [Header(light mode weights)]
       _AmbientWeight("Ambient Weight",Range(0.0,1.0)) = 1.0
              _DiffuseWeight("Diffuse Weight",Range(0.0,1.0)) = 1.0
              _SpecularWeight("Specular Weight",Range(0.0,1.0)) = 1.0
       }
              SubShader
       {
              Tags{ "RenderType" = "Opaque" }
              LOD 100
              Pass
       {
              Tags{ "LightMode" = "ForwardBase" }
              CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase     
#include "Lighting.cginc"
#include "AutoLight.cginc"
              struct appdata
       {
              float4 vertex : POSITION;
              float3 normal:NORMAL;
              float4 tangent:TANGENT;
              float2 uv : TEXCOORD0;
              float2 uv2 : TEXCOORD1;
       };
       struct v2f
       {
              float4 pos : SV_POSITION;
              float3 uv : TEXCOORD0;
              float3 tengentLightDir:TEXCOORD1;
              float3 tangentViewDir:TEXCOORD2;
              SHADOW_COORDS(3)
       };
       sampler2D _MainTex;
       sampler2D _MainTex_1;
       sampler2D _MainTex_2;
       sampler2D _MainTex_3;
       sampler2D _MainTex_4;
       sampler2D _MainTex_5;
       sampler2D _MainTex_6;
       sampler2D _MainTex_7;
       float4 _MainTex_ST;
       half4 _MainTex_TexelSize;
       float4  _TexRect[8];
       fixed4 _Color;
       //sampler2D _AlphaTex;
       //float4 _AlphaTex_ST;
       //fixed _AlphaScale;
       sampler2D _NormalTex;
       float4 _NormalTex_ST;
       half _BumpScale;
       //specular
       fixed4 _Specular;
       half _Gloss;
       //light mode weights
       fixed _AmbientWeight;
       fixed _DiffuseWeight;
       fixed _SpecularWeight;
       v2f vert(appdata v)
       {
              v2f o;
              o.pos = UnityObjectToClipPos(v.vertex);
              o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
              o.uv.z = v.uv2.x;
              TANGENT_SPACE_ROTATION;
              o.tengentLightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
              o.tangentViewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
              TRANSFER_SHADOW(o);
              return o;
       }
       fixed4 frag(v2f i) : SV_Target
       {
              fixed3 tangentLightDir = normalize(i.tengentLightDir);
       fixed3 tangentViewDir = normalize(i.tangentViewDir);
       fixed4 packedNormal = tex2D(_NormalTex, i.uv.xy);
       fixed3 tangentNormal = UnpackNormal(packedNormal);
       tangentNormal.xy *= _BumpScale;
       tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
       int idx = (int)(i.uv.z+0.0001);
       fixed3 texColor;
       if (idx == 0)
       {
              texColor = tex2D(_MainTex, i.uv.xy).rgb;
       }else if(idx == 1)
       {
              texColor = tex2D(_MainTex_1, i.uv.xy).rgb;
       }
       else if (idx == 2)
       {
              texColor = tex2D(_MainTex_2, i.uv.xy).rgb;
       }
       else if (idx == 3)
       {
              texColor = tex2D(_MainTex_3, i.uv.xy).rgb;
       }
       else if (idx == 4)
       {
              texColor = tex2D(_MainTex_4, i.uv.xy).rgb;
       }
       else if (idx == 5)
       {
              texColor = tex2D(_MainTex_5, i.uv.xy).rgb;
       }
       else if (idx == 6)
       {
              texColor = tex2D(_MainTex_6, i.uv.xy).rgb;
       }
       else if (idx == 7)
       {
              texColor = tex2D(_MainTex_7, i.uv.xy).rgb;
       }
       fixed3 abedo = texColor*_Color.rgb;
       return fixed4(abedo,1);
       //
       ////light mode
       //fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*abedo*_AmbientWeight;
       //fixed3 diffuse = _LightColor0.rgb*abedo*saturate(dot(tangentNormal, tangentLightDir))*_DiffuseWeight;
       //fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(tangentNormal, normalize(tangentLightDir + tangentViewDir))), _Gloss)*_SpecularWeight;
       //fixed atten = SHADOW_ATTENUATION(i);
       //return fixed4(ambient + (diffuse + specular)*atten,1);
       }
              ENDCG
       }
       }
              Fallback "Diffuse"
}

斑马线代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

[ExecuteInEditMode]
public class CombineMultiMaterialUV : MonoBehaviour {

    public bool m_debug = false;
    public Shader m_Shader;
    public Material m_Material;

    private void OnEnable()
    {
        //DoReset();
        FindSrcRenderer();
        FindSrcMaterialArray();
        FindSrcTextureArray();
        CombineSrcToGetTargetTexture();


    }
    private void CreateTarget()
    {
        FindOrCreateTargetObject();
        FindOrCreateTargetMeshFilter();
        FindOrCreateRenderer();
        FindOrCreateTargetMaterial();
        DebugLog();
    }
    private void OnDisable()
    {
        DoReset();
    }
    private void DoReset()
    {
        if (m_TargetObj != null)
        {
            DestroyImmediate(m_TargetObj);
            m_TargetObj = null;
        }
        m_TargetMeshFilter = null;
        m_TargetMesh = null;
        m_TargetRenderer = null;
        m_Material = null;
        m_TargetTexture = null;

        m_SrcMesh = null;
        m_SrcRenderer = null;
        m_SrcMaterialArray = null;
        m_SrcTextureArray = null;
        textureTotalSize = Vector2.zero;
        m_Rects = null;
        if (File.Exists(m_createdTexturePath))
        {
            File.Delete(m_createdTexturePath);
        }
    }
    #region debug

    private void DebugLog()
    {
        //debug mesh
        if (m_debug && m_TargetMesh != null)
        {
            Debug.Log("m_TargetMesh.subMeshCount=" + m_TargetMesh.subMeshCount);
        }
    }
#endregion
    #region Mesh
    public MeshFilter m_TargetMeshFilter;
    public Mesh m_TargetMesh;
    public Mesh m_SrcMesh;
    /// <summary>
    /// 查找或创建目标网格过滤器
    /// </summary>
    private void FindOrCreateTargetMeshFilter()
    {
        if (m_TargetObj != null)
        {
            m_TargetMeshFilter = m_TargetObj.GetComponent<MeshFilter>();
            if (m_TargetMeshFilter == null)
            {
                m_TargetMeshFilter = m_TargetObj.AddComponent<MeshFilter>();
                m_SrcMesh = this.GetComponent<MeshFilter>().sharedMesh;
                Debug.Log("SrcMesh Vertex Count="+m_SrcMesh.vertexCount);
                //CreateVertexAsGameObject();
                //m_TargetMesh = MeshUtil.MeshTrueCopy(m_SrcMesh);
                //m_TargetMesh = m_SrcMesh;
                //m_TargetMesh.name = "CMM_" + m_SrcMesh.name;
                //UpdateUvsPerSubmeshByNewTexRect();
                //m_TargetMesh = MeshUtil.MergeSubMesh(m_SrcMesh, m_Rects);//重新计算顶点UV值,缺点是不适用uv范围不在[0,1]的情况
                //m_TargetMesh = MeshUtil.MergeSubMesh(m_SrcMesh);//UV2.U来存储子网格ID
                m_TargetMesh = MeshUtil.MergeSubMeshStoreRect(m_SrcMesh, m_Rects);//将变换的Rect直接存储到顶点uv2和uv3中。
                m_TargetMeshFilter.sharedMesh = m_TargetMesh;
            }
            else
            {
                m_SrcMesh = this.GetComponent<MeshFilter>().sharedMesh;
                m_TargetMesh = m_TargetMeshFilter.sharedMesh;
            }
        }
    }
    private void CreateVertexAsGameObject()
    {
        int i = 0;
        foreach (Vector3 vertex in m_SrcMesh.vertices)
        {
            GameObject go = new GameObject("vertex_" + i);
            go.transform.parent = this.transform;
            go.transform.localPosition = vertex;
            //go.transform.localRotation  = m_SrcMesh.normals[i]
            //go.transform.LookAt(transform.localToWorldMatrix * (vertex + m_SrcMesh.normals[i]));
            Vector3 worldVertex=transform.localToWorldMatrix* vertex;
            Vector3 WorldNormal = transform.localToWorldMatrix * (vertex + m_SrcMesh.normals[i]);
           // Debug.Log("worldVertex"+ worldVertex.ToString());
            //Debug.DrawLine(Vector3.zero, worldVertex*10, Color.red,60.0f);
           // Debug.DrawLine(worldVertex, WorldNormal, Color.green,60.0f);
            i++;
        }
    }
    /// <summary>
    /// 对每一个子网格顶点更新uv,子网格id对应缩放uv用的贴图Rect
    /// </summary>
    private void UpdateUvsPerSubmeshByNewTexRect()
    {
        Debug.Log("UpdateUvsPerSubmeshByNewTexRect");
        if (m_TargetMesh != null)
        {

            if (m_TargetMesh.subMeshCount > 0)
            {
                int[] vertIdxs = new int[m_TargetMesh.vertexCount];
                Vector2[] uvs = new Vector2[m_TargetMesh.vertexCount];
                for (int i = 0; i < m_TargetMesh.subMeshCount; i++)
                {
                    Debug.Log("m_TargetMesh.subMeshCoun index="+i);
                    int[] trianges = m_SrcMesh.GetTriangles(i);
                    //int[] trianges = m_TargetMesh.GetTriangles(i);
                    Debug.Log("m_TargetMesh.subMeshCoun trianges length=" + trianges.Length);
                    int triangesNum = trianges.Length / 3;
                    for (int j = 0; j < triangesNum; j++)
                    {
                        int vertex_1 = trianges[j * 3];
                        int vertex_2 = trianges[j * 3+1];
                        int vertex_3 = trianges[j * 3+2];
                        if (i == 0) {
                        Vector3 start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_1] + m_TargetMesh.normals[vertex_1] * i);
                        Vector3 end = transform.localToWorldMatrix *(m_TargetMesh.vertices[vertex_1]  + m_TargetMesh.normals[vertex_1] * (i + 1));
                        Color color = new Color(i/2.0f, vertex_1/((float)m_TargetMesh.vertexCount), 0);
                        float time = 6000.0f;
                        Debug.DrawLine(start,end,color,time);
                        start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_2] + m_TargetMesh.normals[vertex_2] * i);
                        end = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_2]  + m_TargetMesh.normals[vertex_2] * (i + 1)) ;
                        color = new Color(i / 2.0f, vertex_2 / ((float)m_TargetMesh.vertexCount), 0);
                        Debug.DrawLine(start, end, color, time);
                        start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_3] + m_TargetMesh.normals[vertex_3] * i);
                        end = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_3]  + m_TargetMesh.normals[vertex_3] * (i + 1)) ;
                        color = new Color(i / 2.0f, vertex_3 / ((float)m_TargetMesh.vertexCount), 0);
                        Debug.DrawLine(start, end, color, time);
                        }
                        if (vertIdxs[vertex_1] != 1)
                        {
                            //Debug.Log("refresh uv vertex id = "+ vertex_1+"  uv=" + m_TargetMesh.uv[vertex_1]);
                            vertIdxs[vertex_1] = 1;
                            uvs[vertex_1].x = m_Rects[i].x + m_TargetMesh.uv[vertex_1].x * m_Rects[i].width;
                            uvs[vertex_1].y = m_Rects[i].y + m_TargetMesh.uv[vertex_1].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j + "[1]" + uvs[vertex_1].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid"+ vertex_1 + " " + uvs[vertex_1].ToString());
                            }

                        }
                        if (vertIdxs[vertex_2] != 1)
                        {
                            vertIdxs[vertex_2] = 1;
                            uvs[vertex_2].x = m_Rects[i].x + m_TargetMesh.uv[vertex_2].x * m_Rects[i].width;
                            uvs[vertex_2].y = m_Rects[i].y + m_TargetMesh.uv[vertex_2].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j + "[2]" + uvs[vertex_2].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid" + vertex_2 + " " + uvs[vertex_2].ToString());
                            }

                        }
                        if (vertIdxs[vertex_3] != 1)
                        {
                            vertIdxs[vertex_3] = 1;
                            uvs[vertex_3].x = m_Rects[i].x + m_TargetMesh.uv[vertex_3].x * m_Rects[i].width;
                            uvs[vertex_3].y = m_Rects[i].y + m_TargetMesh.uv[vertex_3].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j+"[3]" + uvs[vertex_3].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid" + vertex_3 + " " + uvs[vertex_3].ToString());
                            }

                        }
                    }
                }
               m_TargetMesh.uv = uvs;
            }
            //m_TargetMesh.subMeshCount = 1;
        }
    }
    private void CombineSubMesh()
    {
        if (m_TargetMesh != null)
        {
            //m_TargetMesh.SetTriangles(,)
        }
    }
    #endregion
    #region Renderer
    public MeshRenderer m_TargetRenderer;
    /// <summary>
    /// 创建渲染器组件
    /// </summary>
    private void FindOrCreateRenderer()
    {
        if (m_TargetObj != null)
        {
            m_TargetRenderer = m_TargetObj.GetComponent<MeshRenderer>();
            if (m_TargetRenderer == null)
            {
                m_TargetRenderer = m_TargetObj.AddComponent<MeshRenderer>();
            }
        }
    }
    public MeshRenderer m_SrcRenderer;
    private void FindSrcRenderer()
    {
        m_SrcRenderer = GetComponent<MeshRenderer>();
    }
    #endregion
    #region Material
    public Material[] m_SrcMaterialArray;
    private void FindSrcMaterialArray() {
        if (m_SrcRenderer != null)
        {
            m_SrcMaterialArray = m_SrcRenderer.sharedMaterials;
        }
    }
    /// <summary>
    /// 创建材质球,并设置合并后的贴图
    /// </summary>
    private void FindOrCreateTargetMaterial()
    {
        if (m_TargetRenderer != null)
        {
            if (m_TargetRenderer.sharedMaterial != null)
            {
                m_Material = m_TargetRenderer.sharedMaterial;
            }
            else
            {
                m_Material = new Material(m_Shader);
                m_TargetRenderer.sharedMaterial = m_Material;
            }
            m_Material.SetTexture("_MainTex", m_TargetTextureLoaded);
            //m_Material.SetVectorArray("_TexRect", RectsToVectors(m_Rects));
        }
    }
    private List<Vector4> RectsToVectors(Rect[] rects)
    {
        List<Vector4> rs = new List<Vector4>();
        if (rects != null && rects.Length > 0)
        {
            foreach (Rect r in rects)
            {
                rs.Add(new Vector4(r.x,r.y,r.width,r.height));
            }
        }
        Debug.Log("RectsToVectors="+ ShowVector4s(rs));
        return rs;
    }
    private string ShowVector4s(List<Vector4> vl)
    {
        string rs = "";
        foreach (Vector4 v in vl)
        {
            rs += " ("+v.x+","+v.y + "," + v.z + "," + v.w + ")";
        }
        return rs;
    }
    #endregion
    #region Texture
    public Texture2D[] m_SrcTextureArray;
    public  Vector2 textureTotalSize = new Vector2(0, 0);
    /// <summary>
    /// 找到源贴图数组
    /// </summary>
    private void FindSrcTextureArray()
    {
        if (m_SrcMaterialArray != null)
        {
            m_SrcTextureArray = new Texture2D[m_SrcMaterialArray.Length];
            textureTotalSize = new Vector2(0, 0);
            for (int i = 0; i < m_SrcMaterialArray.Length; i++)
            {
                Texture2D tex = m_SrcMaterialArray[i].GetTexture("_MainTex") as Texture2D;
                Texture2D texTemp = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
                texTemp.SetPixels(tex.GetPixels(0, 0, tex.width, tex.height));
                texTemp.Apply();
                m_SrcTextureArray[i] = texTemp;
                textureTotalSize.x = Mathf.Max(textureTotalSize.x, texTemp.width);
                textureTotalSize.y += texTemp.height;
            }
            textureTotalSize.x += 10*(m_SrcMaterialArray.Length-1);
            textureTotalSize.y += 10 * (m_SrcMaterialArray.Length - 1);
            textureTotalSize = TextureSizeToPowerFormat(textureTotalSize);
        }
    }
    public Vector2 TextureSizeToPowerFormat(Vector2 i)
    {
        Debug.Log("TextureSizeToPowerFormat textureTotalSize=" + i);
        int avg = (int)((i.x + i.y) / 2);
        i.x = avg;
        i.y = avg;
        Vector2 o = new Vector2(0, 0);
        for (int p = 1; p < 14; p++)
        {
            int pp0 = (int)Mathf.Pow(2, p-1);
            int pp1 = (int)Mathf.Pow(2, p);
            if (i.x > pp0 && i.x <= pp1)
            {
                o.x = pp1;
            }
            if (i.y > pp0 && i.y <= pp1)
            {
                o.y = pp1;
            }
        }
        if (o.x > 4096)
        {
            o.x = 4096;
        }
        if (o.y > 4096)
        {
            o.y = 4096;
        }
        Debug.Log("TextureSizeToPowerFormat textureTotalSize out=" + o);
        return o;
    }
    public Texture2D m_TargetTexture;
    public Texture2D m_TargetTextureLoaded;
    public Rect[] m_Rects;
    public int maximumAtlasSize=2048;
    public int padding = 0;
    public string m_createdTexturePath = "";
    public string m_createdTextureName = "cube_diffuse.jpeg";
    /// <summary>
    /// 合并贴图到目标图集中
    /// </summary>
    private void CombineSrcToGetTargetTexture()
    {
        Debug.Log("textureTotalSize=" + textureTotalSize);
        m_TargetTexture = new Texture2D((int)textureTotalSize.x, (int)textureTotalSize.y);
        m_Rects = m_TargetTexture.PackTextures(m_SrcTextureArray, padding, maximumAtlasSize);
        //m_TargetTexture.Compress(false);

        //string url = Application.persistentDataPath + @"\Merge\";
        string dir = Application.dataPath + @"/Resources/Merge/";
        Debug.Log("TagetTexture dir=" + dir);
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        m_createdTexturePath = dir + m_createdTextureName;
        Debug.Log("TagetTexture m_createdTexturePath=" + m_createdTexturePath + "  file exists:" + File.Exists(m_createdTexturePath));
        if (File.Exists(m_createdTexturePath))
        {
            File.Delete(m_createdTexturePath);
        }
        Debug.Log("  file exists:" + File.Exists(m_createdTexturePath));
        File.WriteAllBytes(m_createdTexturePath, m_TargetTexture.EncodeToJPG());
        //m_TargetTexture = Resources.Load<Texture2D>(m_createdTexturePath);
        StartCoroutine("LoadTargetTexture");

    }
    private IEnumerator LoadTargetTexture()
    {
        WWW www = new WWW("file://" + m_createdTexturePath);
        yield return www.isDone;
        m_TargetTextureLoaded = www.texture;
        CreateTarget();
    }
    #endregion
    #region TargetObj
    public GameObject m_TargetObj;
    private void FindOrCreateTargetObject()
    {
        string name = this.gameObject.name + "_CombineMultiMaterial";
        if (this.transform.parent == null)
        {
            m_TargetObj = GameObject.Find(name);
            if (m_TargetObj == null)
            {
                CreateTargetObj(name);
            }
        }
        else
        {
            Transform tar = this.transform.parent.Find(name);
            if (tar == null)
            {
                CreateTargetObj(name);
            }
            else
            {
                m_TargetObj = tar.gameObject;
            }
        }


    }
    private void CreateTargetObj(string name)
    {
        m_TargetObj = new GameObject(name);
        m_TargetObj.transform.parent = this.transform.parent;
        m_TargetObj.transform.position = Vector3.zero;
        m_TargetObj.transform.rotation = Quaternion.identity;
    }
#endregion
}


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class MeshUtil{
    [MenuItem("Tools/Combine SubMesh & M")]
    public static void CombineSubMesh()
    {
        GameObject go = Selection.activeGameObject;
        if (go)
        {
            MeshFilter mf = go.GetComponent<MeshFilter>();
            if (mf)
            {
                Mesh mesh = mf.sharedMesh;
                if (mesh)
                {
                    Mesh cMesh = MeshUtil.MergeSubMesh(mesh);
                    if (cMesh)
                    {
                        string meshPath = "Assets/__source/Model/Combined/" + cMesh.name + ".asset";
                        AssetDatabase.DeleteAsset(meshPath);
                        AssetDatabase.CreateAsset(cMesh, meshPath);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 深度复制网格
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public static Mesh MeshTrueCopy(Mesh i)
    {
        Mesh o = new Mesh();

        o.name = i.name;
        o.hideFlags = i.hideFlags;
        //顶点 位置 方向
        o.vertices = i.vertices;
        o.normals = i.normals;
        o.tangents = i.tangents;
        //三角面
        o.triangles = i.triangles;
        o.subMeshCount = i.subMeshCount;
        //颜色
        o.uv = i.uv;
        int dCount = 50;
        for(int j=0;j<o.vertexCount;j++)
        {
            if (dCount > 0&&(Mathf.Abs(o.uv[j].x)>1|| Mathf.Abs(o.uv[j].y) > 1))
            {
                dCount--;
                Debug.Log("uv=" + o.uv[j].x+" "+o.uv[j].y);
            }
            if (dCount == 0)
            {
                break;
            }
        }

        o.uv2 = i.uv2;
        o.uv3 = i.uv3;
        o.uv4 = i.uv4;
        o.colors = i.colors;
        o.colors32 = i.colors32;
        //边缘
        o.bounds = i.bounds;
        //骨骼
        o.boneWeights = i.boneWeights;
        o.bindposes = i.bindposes;
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// 同时更新UV
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh,Rect[] texRects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);

        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();
                CopyAndAddVertexs(hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            Debug.Log("更新UV前此子网格各顶点的UV值【"+ ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            UpdateUv(newSubmeshTrianges, texRects[i],ref tarUVList);
            Debug.Log("Rect【"+texRects[i].ToString()+"】更新UV后此子网格各顶点的UV值【" + ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static string ShowUVsi(int[] newSubmeshTriange, List<Vector2> tarUVList)
    {
        string rs = "[";
        foreach (int idx in newSubmeshTriange)
        {
            rs+= idx+":(" +tarUVList[idx].x+","+ tarUVList[idx].y+")|";
        }
        return rs+"]";
    }
    public static void UpdateUv(int[] newSubmeshTrianges,Rect texRect,ref List<Vector2> tarUVList)
    {
        List<int> vertexIndexs_noRepeat = ArrayRemoveDuplication(newSubmeshTrianges);
        foreach (int idx in vertexIndexs_noRepeat)
        {
            float x = texRect.x + UVToZeroOne(tarUVList[idx].x) * texRect.width;
            float y = texRect.y + UVToZeroOne(tarUVList[idx].y) * texRect.height;
            if (idx == 0)
            {
                Debug.Log("idx="+idx+"  x="+x+"  old x="+ tarUVList[idx].x+ "  UVToZeroOne=" + UVToZeroOne(tarUVList[idx].x) + " texRect="+texRect.ToString());
            }
            tarUVList[idx] = new Vector2(x,y);
        }
    }
    public static float UVToZeroOne(float i)
    {
        float o = 0;
        o = i - Mathf.Floor(i);
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【"+i+"】拥有三角形数量为【"+(srcSubmeshTriangeArray.Length/3)+"】顶点索引为【"+ ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【"+ ShowArrayElements(hadSharedVertexIndexArr) +"】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【"+ tarVertexList.Count+ "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i,hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList,ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【"+ ShowDictionary(vertexIndexRef)+ "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【"+ ShowArrayElements(newSubmeshTrianges)+ "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【"+i+"】循环结束,未更新三角形顶点索引为【"+ShowListElements(srcBeforCurrentSubmeshTrianges)+"】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_"+srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMeshStoreRect(Mesh srcMesh,Rect[] rects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<Vector2> tarUV3List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        tarUV3List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i, hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            //UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            StoreRectToUV(newSubmeshTrianges, rects[i], ref tarUV2List, ref tarUV3List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.uv3 = tarUV3List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static void StoreRectToUV(int[] newSubmeshTrianges,Rect rect,ref List<Vector2> uv2,ref List<Vector2> uv3)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2(rect.x, rect.y);
                uv3[vIdx] = new Vector2(rect.width, rect.height);
            }
        }
    }
    public static void UdateUv2(int currSubmeshId, int[] newSubmeshTrianges, ref List<Vector2> uv2)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2((float)currSubmeshId,0.0f);
            }
        }
        //Debug.Log("UV2="+ ShowUVs(uv2));
    }
    public static string ShowUVs(List<Vector2> uv2)
    {
        string rs = "";
        for(int i=0;i<uv2.Count; i++)
        {
            rs += i+"["+uv2[i].x+","+uv2[i].y+"] ";
        }
        return rs;
    }
    public static int[] UpdateTrianges(int[] oldTrianges,Dictionary<int,int> idxRef)
    {
        int[] newTrianges = new int[oldTrianges.Length];
        for (int i = 0; i < oldTrianges.Length; i++)
        {
            if (idxRef.ContainsKey(oldTrianges[i]))
            {
                newTrianges[i] = idxRef[oldTrianges[i]];
            }
            else
            {
                newTrianges[i] = oldTrianges[i];
            }
        }
        return newTrianges;
    }
    public static int[] CopyArray(int[] arr)
    {
        int[] o = new int[arr.Length];
        for (int i = 0; i < arr.Length; i++)
        {
            o[i] = arr[i];
        }
        return o;
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// </summary>
    /// <param name="vIndexArr"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int[] vIndexArr, Vector2[] srcUVList,
                                        ref List<Vector3> oldVextexList,
                                        ref List<Vector3> oldNormalList,
                                        ref List<Vector2> oldUVList,
                                        ref Dictionary<int,int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref List<Vector2> oldUV3List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh, 0.0f));
                oldUV3List.Add(new Vector2((float)currentSubmesh, 0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh,0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 初始化顶点或法线列表
    /// </summary>
    /// <param name="srcVertexArray"></param>
    /// <returns></returns>
    public static List<Vector3> initVertexOrNormalList(Vector3[] srcVertexArray)
    {
        List<Vector3> vList = new List<Vector3>();
        if (!(srcVertexArray == null || srcVertexArray.Length == 0))
        {
            foreach (Vector3 e in srcVertexArray)
            {
                vList.Add(e);
            }
        }
        return vList;
    }
    /// <summary>
    /// 初始化UV列表
    /// </summary>
    /// <param name="srcUvArray"></param>
    /// <returns></returns>
    public static List<Vector2> initUvList(Vector2[] srcUvArray)
    {
        List<Vector2> uvList = new List<Vector2>();
        if (!(srcUvArray == null || srcUvArray.Length == 0))
        {
            foreach (Vector2 e in srcUvArray)
            {
                uvList.Add(e);
            }
        }
        return uvList;
    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] MergeArrayToArray(int[] arr1,int[] arr2)
    {
        if (arr1 == null || arr1.Length == 0)
        {
            return arr2;
        }
        else if (arr2 == null || arr2.Length == 0)
        {
            return arr1;
        }
        else
        {
            int[] mergeArr =new int[arr1.Length + arr2.Length];
            for (int i = 0; i < arr1.Length; i++)
            {
                mergeArr[i] = arr1[i];
            }
            for (int i = 0; i < arr2.Length; i++)
            {
                mergeArr[arr1.Length+i] = arr2[i];
            }
            return mergeArr;
        }

    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static List<int> MergeArrayToList(int[] arr1, int[] arr2)
    {
        int[] arr = MergeArrayToArray(arr1,arr2);
        List<int> list = new List<int>();
        if (!(arr == null || arr.Length == 0))
        {
            foreach (int e in arr)
            {
                list.Add(e);
            }
        }
        return list;
    }
    /// <summary>
    /// 去除数组中的重复元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static List<int> ArrayRemoveDuplication(int [] arr)
    {
        List<int> list = new List<int>();
        foreach (int i in arr)
        {
            if (!list.Contains(i))
            {
                list.Add(i);
            }
        }
        return list;
    }
    /// <summary>
    /// 找出数组2在数组1中已包含的元素
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] ArrayFindSharedElements(int[] arr1, int[] arr2)
    {
        List<int> list1_noRepeat = ArrayRemoveDuplication(arr1);
        List<int> list2_noRepeat = ArrayRemoveDuplication(arr2);
        List<int> comm = new List<int>();
        foreach (int e in list2_noRepeat)
        {
            if (list1_noRepeat.Contains(e))
            {
                comm.Add(e);
            }
        }
        return comm.ToArray();
    }
    /// <summary>
    /// 显示数组元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static string ShowArrayElements(int[] arr)
    {
        string rs = "[";
        foreach(int i in arr)
        {
            rs += i + " ";
        }
        return rs+"]";
    }
    public static string ShowListElements(List<int> list)
    {
        return ShowArrayElements(list.ToArray());
    }
    public static string ShowDictionary(Dictionary<int,int> dic)
    {
        string rs = "";
        foreach (int k in dic.Keys)
        {
            rs += k + "-->" + dic[k] + "|";
        }
        return rs;
    }
}


Shader "6/Room_Ruin_2_Opaque_UV"
{
       Properties
       {
              _MainTex("Abedo", 2D) = "white" {}
       _Color("Abedo Color",Color) = (1,1,1,1)
              //_AlphaTex("Alpha",2D) = ""{}
              //_AlphaScale("Alpha Scale",Range(0.0,1.0))=1.0
              _NormalTex("Normal",2D) = "bump"{}
       _BumpScale("Normal/Bump Scale",Range(0.0,3.0)) = 1.0
              [Header(specular)]
       _Specular("Specular",Color) = (1,1,1,1)
              _Gloss("Gloss",Range(8,256)) = 20
              [Header(light mode weights)]
       _AmbientWeight("Ambient Weight",Range(0.0,1.0)) = 1.0
              _DiffuseWeight("Diffuse Weight",Range(0.0,1.0)) = 1.0
              _SpecularWeight("Specular Weight",Range(0.0,1.0)) = 1.0
       }
              SubShader
       {
              Tags{ "RenderType" = "Opaque" }
              LOD 100
              Pass
       {
              Tags{ "LightMode" = "ForwardBase" }
              CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase     
#include "Lighting.cginc"
#include "AutoLight.cginc"
              struct appdata
       {
              float4 vertex : POSITION;
              float3 normal:NORMAL;
              float4 tangent:TANGENT;
              float2 uv : TEXCOORD0;
              float2 uv1 : TEXCOORD1;
              float2 uv2 : TEXCOORD2;
       };
       struct v2f
       {
              float4 pos : SV_POSITION;
              float2 uv : TEXCOORD0;
              float2 uv1 : TEXCOORD1;
              float2 uv2 : TEXCOORD2;
              float3 tengentLightDir:TEXCOORD3;
              float3 tangentViewDir:TEXCOORD4;
              SHADOW_COORDS(5)
       };
       sampler2D _MainTex;
       float4 _MainTex_ST;
       half4 _MainTex_TexelSize;
       fixed4 _Color;
       //sampler2D _AlphaTex;
       //float4 _AlphaTex_ST;
       //fixed _AlphaScale;
       sampler2D _NormalTex;
       float4 _NormalTex_ST;
       half _BumpScale;
       //specular
       fixed4 _Specular;
       half _Gloss;
       //light mode weights
       fixed _AmbientWeight;
       fixed _DiffuseWeight;
       fixed _SpecularWeight;
       v2f vert(appdata v)
       {
              v2f o;
              o.pos = UnityObjectToClipPos(v.vertex);
              o.uv = TRANSFORM_TEX(v.uv, _MainTex);
              o.uv1 = v.uv1;
              o.uv2 = v.uv2;
              TANGENT_SPACE_ROTATION;
              o.tengentLightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
              o.tangentViewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
              TRANSFER_SHADOW(o);
              return o;
       }
       fixed4 frag(v2f i) : SV_Target
       {
              fixed3 tangentLightDir = normalize(i.tengentLightDir);
       fixed3 tangentViewDir = normalize(i.tangentViewDir);
       fixed4 packedNormal = tex2D(_NormalTex, i.uv);
       fixed3 tangentNormal = UnpackNormal(packedNormal);
       tangentNormal.xy *= _BumpScale;
       tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
       
       float4 rect = float4(i.uv1.x, i.uv1.y,i.uv2.x,i.uv2.y);
       //fixed2 uv = i.uv.xy - floor(i.uv.xy);
       
       float u = i.uv.x;// -floor(i.uv.x) + _MainTex_TexelSize.x * 500;
       float v = i.uv.y;
       if (u < 0 || v < 0)
       {
              //discard;
       }
       float2 leftbuttom = float2(floor(u),floor(v));
       float2 uvTemp = i.uv;
       u = uvTemp.x;
       v = uvTemp.y;
       int ipU = 0;
       int ipV = 0;
       float deltaU = modf(u,ipU);
       float deltaV = modf(v, ipV);
       //u = deltaU;
       //v = deltaV;
       //u = saturate(u);
       //v = saturate(v);
       //deltaU = 1+deltaU
       if (deltaU < 0.1||deltaU>0.9|| deltaV<0.1 || deltaV>0.9)
       {
              //return fixed4(0,0,1,1);
              //u = _MainTex_TexelSize.x;
              //v = _MainTex_TexelSize.y;
              //discard;
              //u =
       }
       else
       {
              //u = u - floor(u);
              //v = v - floor(v);
       }
       u = u - floor(u);
       v = v - floor(v);
       u = rect.x + u*rect.z;
       v = rect.y + v*rect.w;
       fixed3 abedo = tex2D(_MainTex, float2(u, v)).rgb*_Color.rgb;
       return fixed4(abedo, 1);
       //float u = frac(i.uv.x);
       //u = rect.x + u*rect.z;
       //float v = i.uv.y;// -floor(i.uv.y);
       //float v = frac(i.uv.y);
       //v = rect.y + v*rect.w;
       //fixed3 abedo = tex2D(_MainTex, float2(u,v)).rgb*_Color.rgb;
       //return fixed4(abedo,1);
       //
       ////light mode
       //fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*abedo*_AmbientWeight;
       //fixed3 diffuse = _LightColor0.rgb*abedo*saturate(dot(tangentNormal, tangentLightDir))*_DiffuseWeight;
       //fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(tangentNormal, normalize(tangentLightDir + tangentViewDir))), _Gloss)*_SpecularWeight;
       //fixed atten = SHADOW_ATTENUATION(i);
       //return fixed4(ambient + (diffuse + specular)*atten,1);
       }
              ENDCG
       }
       }
              Fallback "Diffuse"
}

方案1:对于网格贴图坐标在【0,1】范围内的游戏物体,可以合并贴图。
          UV超出范围【0,1】的效果图:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

[ExecuteInEditMode]
public class CombineMultiMaterial : MonoBehaviour {

    public bool m_debug = false;
    public Shader m_Shader;
    public Material m_Material;

    private void OnEnable()
    {
        //DoReset();
        FindSrcRenderer();
        FindSrcMaterialArray();
        FindSrcTextureArray();
        CombineSrcToGetTargetTexture();


    }
    private void CreateTarget()
    {
        FindOrCreateTargetObject();
        FindOrCreateTargetMeshFilter();
        FindOrCreateRenderer();
        FindOrCreateTargetMaterial();
        DebugLog();
    }
    private void OnDisable()
    {
        DoReset();
    }
    private void DoReset()
    {
        if (m_TargetObj != null)
        {
            DestroyImmediate(m_TargetObj);
            m_TargetObj = null;
        }
        m_TargetMeshFilter = null;
        m_TargetMesh = null;
        m_TargetRenderer = null;
        m_Material = null;
        m_TargetTexture = null;

        m_SrcMesh = null;
        m_SrcRenderer = null;
        m_SrcMaterialArray = null;
        m_SrcTextureArray = null;
        textureTotalSize = Vector2.zero;
        m_Rects = null;
        if (File.Exists(m_createdTexturePath))
        {
            File.Delete(m_createdTexturePath);
        }
    }
    #region debug

    private void DebugLog()
    {
        //debug mesh
        if (m_debug && m_TargetMesh != null)
        {
            Debug.Log("m_TargetMesh.subMeshCount=" + m_TargetMesh.subMeshCount);
        }
    }
#endregion
    #region Mesh
    public MeshFilter m_TargetMeshFilter;
    public Mesh m_TargetMesh;
    public Mesh m_SrcMesh;
    /// <summary>
    /// 查找或创建目标网格过滤器
    /// </summary>
    private void FindOrCreateTargetMeshFilter()
    {
        if (m_TargetObj != null)
        {
            m_TargetMeshFilter = m_TargetObj.GetComponent<MeshFilter>();
            if (m_TargetMeshFilter == null)
            {
                m_TargetMeshFilter = m_TargetObj.AddComponent<MeshFilter>();
                m_SrcMesh = this.GetComponent<MeshFilter>().sharedMesh;
                Debug.Log("SrcMesh Vertex Count="+m_SrcMesh.vertexCount);
                //CreateVertexAsGameObject();
                //m_TargetMesh = MeshUtil.MeshTrueCopy(m_SrcMesh);
                //m_TargetMesh = m_SrcMesh;
                //m_TargetMesh.name = "CMM_" + m_SrcMesh.name;
                //UpdateUvsPerSubmeshByNewTexRect();
                m_TargetMesh = MeshUtil.MergeSubMesh(m_SrcMesh, m_Rects);
                //m_TargetMesh = MeshUtil.MergeSubMesh(m_SrcMesh);//UV2.U来存储子网格ID
                m_TargetMeshFilter.sharedMesh = m_TargetMesh;
            }
            else
            {
                m_SrcMesh = this.GetComponent<MeshFilter>().sharedMesh;
                m_TargetMesh = m_TargetMeshFilter.sharedMesh;
            }
        }
    }
    private void CreateVertexAsGameObject()
    {
        int i = 0;
        foreach (Vector3 vertex in m_SrcMesh.vertices)
        {
            GameObject go = new GameObject("vertex_" + i);
            go.transform.parent = this.transform;
            go.transform.localPosition = vertex;
            //go.transform.localRotation  = m_SrcMesh.normals[i]
            //go.transform.LookAt(transform.localToWorldMatrix * (vertex + m_SrcMesh.normals[i]));
            Vector3 worldVertex=transform.localToWorldMatrix* vertex;
            Vector3 WorldNormal = transform.localToWorldMatrix * (vertex + m_SrcMesh.normals[i]);
           // Debug.Log("worldVertex"+ worldVertex.ToString());
            //Debug.DrawLine(Vector3.zero, worldVertex*10, Color.red,60.0f);
           // Debug.DrawLine(worldVertex, WorldNormal, Color.green,60.0f);
            i++;
        }
    }
    /// <summary>
    /// 对每一个子网格顶点更新uv,子网格id对应缩放uv用的贴图Rect
    /// </summary>
    private void UpdateUvsPerSubmeshByNewTexRect()
    {
        Debug.Log("UpdateUvsPerSubmeshByNewTexRect");
        if (m_TargetMesh != null)
        {

            if (m_TargetMesh.subMeshCount > 0)
            {
                int[] vertIdxs = new int[m_TargetMesh.vertexCount];
                Vector2[] uvs = new Vector2[m_TargetMesh.vertexCount];
                for (int i = 0; i < m_TargetMesh.subMeshCount; i++)
                {
                    Debug.Log("m_TargetMesh.subMeshCoun index="+i);
                    int[] trianges = m_SrcMesh.GetTriangles(i);
                    //int[] trianges = m_TargetMesh.GetTriangles(i);
                    Debug.Log("m_TargetMesh.subMeshCoun trianges length=" + trianges.Length);
                    int triangesNum = trianges.Length / 3;
                    for (int j = 0; j < triangesNum; j++)
                    {
                        int vertex_1 = trianges[j * 3];
                        int vertex_2 = trianges[j * 3+1];
                        int vertex_3 = trianges[j * 3+2];
                        if (i == 0) {
                        Vector3 start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_1] + m_TargetMesh.normals[vertex_1] * i);
                        Vector3 end = transform.localToWorldMatrix *(m_TargetMesh.vertices[vertex_1]  + m_TargetMesh.normals[vertex_1] * (i + 1));
                        Color color = new Color(i/2.0f, vertex_1/((float)m_TargetMesh.vertexCount), 0);
                        float time = 6000.0f;
                        Debug.DrawLine(start,end,color,time);
                        start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_2] + m_TargetMesh.normals[vertex_2] * i);
                        end = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_2]  + m_TargetMesh.normals[vertex_2] * (i + 1)) ;
                        color = new Color(i / 2.0f, vertex_2 / ((float)m_TargetMesh.vertexCount), 0);
                        Debug.DrawLine(start, end, color, time);
                        start = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_3] + m_TargetMesh.normals[vertex_3] * i);
                        end = transform.localToWorldMatrix * (m_TargetMesh.vertices[vertex_3]  + m_TargetMesh.normals[vertex_3] * (i + 1)) ;
                        color = new Color(i / 2.0f, vertex_3 / ((float)m_TargetMesh.vertexCount), 0);
                        Debug.DrawLine(start, end, color, time);
                        }
                        if (vertIdxs[vertex_1] != 1)
                        {
                            //Debug.Log("refresh uv vertex id = "+ vertex_1+"  uv=" + m_TargetMesh.uv[vertex_1]);
                            vertIdxs[vertex_1] = 1;
                            uvs[vertex_1].x = m_Rects[i].x + m_TargetMesh.uv[vertex_1].x * m_Rects[i].width;
                            uvs[vertex_1].y = m_Rects[i].y + m_TargetMesh.uv[vertex_1].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j + "[1]" + uvs[vertex_1].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid"+ vertex_1 + " " + uvs[vertex_1].ToString());
                            }

                        }
                        if (vertIdxs[vertex_2] != 1)
                        {
                            vertIdxs[vertex_2] = 1;
                            uvs[vertex_2].x = m_Rects[i].x + m_TargetMesh.uv[vertex_2].x * m_Rects[i].width;
                            uvs[vertex_2].y = m_Rects[i].y + m_TargetMesh.uv[vertex_2].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j + "[2]" + uvs[vertex_2].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid" + vertex_2 + " " + uvs[vertex_2].ToString());
                            }

                        }
                        if (vertIdxs[vertex_3] != 1)
                        {
                            vertIdxs[vertex_3] = 1;
                            uvs[vertex_3].x = m_Rects[i].x + m_TargetMesh.uv[vertex_3].x * m_Rects[i].width;
                            uvs[vertex_3].y = m_Rects[i].y + m_TargetMesh.uv[vertex_3].y * m_Rects[i].height;
                            if (i > 0)
                            {
                                Debug.Log(j+"[3]" + uvs[vertex_3].ToString());
                            }
                        }
                        else
                        {
                            if (i > 0)
                            {
                                Debug.Log(j + "[had refrush] vid" + vertex_3 + " " + uvs[vertex_3].ToString());
                            }

                        }
                    }
                }
               m_TargetMesh.uv = uvs;
            }
            //m_TargetMesh.subMeshCount = 1;
        }
    }
    private void CombineSubMesh()
    {
        if (m_TargetMesh != null)
        {
            //m_TargetMesh.SetTriangles(,)
        }
    }
    #endregion
    #region Renderer
    public MeshRenderer m_TargetRenderer;
    /// <summary>
    /// 创建渲染器组件
    /// </summary>
    private void FindOrCreateRenderer()
    {
        if (m_TargetObj != null)
        {
            m_TargetRenderer = m_TargetObj.GetComponent<MeshRenderer>();
            if (m_TargetRenderer == null)
            {
                m_TargetRenderer = m_TargetObj.AddComponent<MeshRenderer>();
            }
        }
    }
    public MeshRenderer m_SrcRenderer;
    private void FindSrcRenderer()
    {
        m_SrcRenderer = GetComponent<MeshRenderer>();
    }
    #endregion
    #region Material
    public Material[] m_SrcMaterialArray;
    private void FindSrcMaterialArray() {
        if (m_SrcRenderer != null)
        {
            m_SrcMaterialArray = m_SrcRenderer.sharedMaterials;
        }
    }
    /// <summary>
    /// 创建材质球,并设置合并后的贴图
    /// </summary>
    private void FindOrCreateTargetMaterial()
    {
        if (m_TargetRenderer != null)
        {
            if (m_TargetRenderer.sharedMaterial != null)
            {
                m_Material = m_TargetRenderer.sharedMaterial;
            }
            else
            {
                m_Material = new Material(m_Shader);
                m_TargetRenderer.sharedMaterial = m_Material;
            }
            m_Material.SetTexture("_MainTex", m_TargetTextureLoaded);
            //m_Material.SetVectorArray("_TexRect", RectsToVectors(m_Rects));
        }
    }
    private List<Vector4> RectsToVectors(Rect[] rects)
    {
        List<Vector4> rs = new List<Vector4>();
        if (rects != null && rects.Length > 0)
        {
            foreach (Rect r in rects)
            {
                rs.Add(new Vector4(r.x,r.y,r.width,r.height));
            }
        }
        Debug.Log("RectsToVectors="+ ShowVector4s(rs));
        return rs;
    }
    private string ShowVector4s(List<Vector4> vl)
    {
        string rs = "";
        foreach (Vector4 v in vl)
        {
            rs += " ("+v.x+","+v.y + "," + v.z + "," + v.w + ")";
        }
        return rs;
    }
    #endregion
    #region Texture
    public Texture2D[] m_SrcTextureArray;
    public  Vector2 textureTotalSize = new Vector2(0, 0);
    /// <summary>
    /// 找到源贴图数组
    /// </summary>
    private void FindSrcTextureArray()
    {
        if (m_SrcMaterialArray != null)
        {
            m_SrcTextureArray = new Texture2D[m_SrcMaterialArray.Length];
            textureTotalSize = new Vector2(0, 0);
            for (int i = 0; i < m_SrcMaterialArray.Length; i++)
            {
                Texture2D tex = m_SrcMaterialArray[i].GetTexture("_MainTex") as Texture2D;
                Texture2D texTemp = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
                texTemp.SetPixels(tex.GetPixels(0, 0, tex.width, tex.height));
                texTemp.Apply();
                m_SrcTextureArray[i] = texTemp;
                textureTotalSize.x = Mathf.Max(textureTotalSize.x, texTemp.width);
                textureTotalSize.y += texTemp.height;
            }
            textureTotalSize.x += 10*(m_SrcMaterialArray.Length-1);
            textureTotalSize.y += 10 * (m_SrcMaterialArray.Length - 1);
            textureTotalSize = TextureSizeToPowerFormat(textureTotalSize);
        }
    }
    public Vector2 TextureSizeToPowerFormat(Vector2 i)
    {
        Debug.Log("TextureSizeToPowerFormat textureTotalSize=" + i);
        int avg = (int)((i.x + i.y) / 2);
        i.x = avg;
        i.y = avg;
        Vector2 o = new Vector2(0, 0);
        for (int p = 1; p < 14; p++)
        {
            int pp0 = (int)Mathf.Pow(2, p-1);
            int pp1 = (int)Mathf.Pow(2, p);
            if (i.x > pp0 && i.x <= pp1)
            {
                o.x = pp1;
            }
            if (i.y > pp0 && i.y <= pp1)
            {
                o.y = pp1;
            }
        }
        if (o.x > 4096)
        {
            o.x = 4096;
        }
        if (o.y > 4096)
        {
            o.y = 4096;
        }
        Debug.Log("TextureSizeToPowerFormat textureTotalSize out=" + o);
        return o;
    }
    public Texture2D m_TargetTexture;
    public Texture2D m_TargetTextureLoaded;
    public Rect[] m_Rects;
    public int maximumAtlasSize=2048;
    public int padding = 0;
    public string m_createdTexturePath = "";
    public string m_createdTextureName = "cube_diffuse.jpeg";
    /// <summary>
    /// 合并贴图到目标图集中
    /// </summary>
    private void CombineSrcToGetTargetTexture()
    {
        Debug.Log("textureTotalSize=" + textureTotalSize);
        m_TargetTexture = new Texture2D((int)textureTotalSize.x, (int)textureTotalSize.y);
        m_Rects = m_TargetTexture.PackTextures(m_SrcTextureArray, padding, maximumAtlasSize);
        //m_TargetTexture.Compress(false);

        //string url = Application.persistentDataPath + @"\Merge\";
        string dir = Application.dataPath + @"/Resources/Merge/";
        Debug.Log("TagetTexture dir=" + dir);
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        m_createdTexturePath = dir + m_createdTextureName;
        Debug.Log("TagetTexture m_createdTexturePath=" + m_createdTexturePath + "  file exists:" + File.Exists(m_createdTexturePath));
        if (File.Exists(m_createdTexturePath))
        {
            File.Delete(m_createdTexturePath);
        }
        Debug.Log("  file exists:" + File.Exists(m_createdTexturePath));
        File.WriteAllBytes(m_createdTexturePath, m_TargetTexture.EncodeToJPG());
        //m_TargetTexture = Resources.Load<Texture2D>(m_createdTexturePath);
        StartCoroutine("LoadTargetTexture");

    }
    private IEnumerator LoadTargetTexture()
    {
        WWW www = new WWW("file://" + m_createdTexturePath);
        yield return www.isDone;
        m_TargetTextureLoaded = www.texture;
        CreateTarget();
    }
    #endregion
    #region TargetObj
    public GameObject m_TargetObj;
    private void FindOrCreateTargetObject()
    {
        string name = this.gameObject.name + "_CombineMultiMaterial";
        if (this.transform.parent == null)
        {
            m_TargetObj = GameObject.Find(name);
            if (m_TargetObj == null)
            {
                CreateTargetObj(name);
            }
        }
        else
        {
            Transform tar = this.transform.parent.Find(name);
            if (tar == null)
            {
                CreateTargetObj(name);
            }
            else
            {
                m_TargetObj = tar.gameObject;
            }
        }


    }
    private void CreateTargetObj(string name)
    {
        m_TargetObj = new GameObject(name);
        m_TargetObj.transform.parent = this.transform.parent;
        m_TargetObj.transform.position = Vector3.zero;
        m_TargetObj.transform.rotation = Quaternion.identity;
    }
#endregion
}


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class MeshUtil{
    [MenuItem("Tools/Combine SubMesh & M")]
    public static void CombineSubMesh()
    {
        GameObject go = Selection.activeGameObject;
        if (go)
        {
            MeshFilter mf = go.GetComponent<MeshFilter>();
            if (mf)
            {
                Mesh mesh = mf.sharedMesh;
                if (mesh)
                {
                    Mesh cMesh = MeshUtil.MergeSubMesh(mesh);
                    if (cMesh)
                    {
                        string meshPath = "Assets/__source/Model/Combined/" + cMesh.name + ".asset";
                        AssetDatabase.DeleteAsset(meshPath);
                        AssetDatabase.CreateAsset(cMesh, meshPath);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 深度复制网格
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public static Mesh MeshTrueCopy(Mesh i)
    {
        Mesh o = new Mesh();

        o.name = i.name;
        o.hideFlags = i.hideFlags;
        //顶点 位置 方向
        o.vertices = i.vertices;
        o.normals = i.normals;
        o.tangents = i.tangents;
        //三角面
        o.triangles = i.triangles;
        o.subMeshCount = i.subMeshCount;
        //颜色
        o.uv = i.uv;
        int dCount = 50;
        for(int j=0;j<o.vertexCount;j++)
        {
            if (dCount > 0&&(Mathf.Abs(o.uv[j].x)>1|| Mathf.Abs(o.uv[j].y) > 1))
            {
                dCount--;
                Debug.Log("uv=" + o.uv[j].x+" "+o.uv[j].y);
            }
            if (dCount == 0)
            {
                break;
            }
        }

        o.uv2 = i.uv2;
        o.uv3 = i.uv3;
        o.uv4 = i.uv4;
        o.colors = i.colors;
        o.colors32 = i.colors32;
        //边缘
        o.bounds = i.bounds;
        //骨骼
        o.boneWeights = i.boneWeights;
        o.bindposes = i.bindposes;
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// 同时更新UV
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh,Rect[] texRects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);

        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();
                CopyAndAddVertexs(hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            Debug.Log("更新UV前此子网格各顶点的UV值【"+ ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            UpdateUv(newSubmeshTrianges, texRects[i],ref tarUVList);
            Debug.Log("Rect【"+texRects[i].ToString()+"】更新UV后此子网格各顶点的UV值【" + ShowUVsi(newSubmeshTrianges, tarUVList) + "】");
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static string ShowUVsi(int[] newSubmeshTriange, List<Vector2> tarUVList)
    {
        string rs = "[";
        foreach (int idx in newSubmeshTriange)
        {
            rs+= idx+":(" +tarUVList[idx].x+","+ tarUVList[idx].y+")|";
        }
        return rs+"]";
    }
    public static void UpdateUv(int[] newSubmeshTrianges,Rect texRect,ref List<Vector2> tarUVList)
    {
        List<int> vertexIndexs_noRepeat = ArrayRemoveDuplication(newSubmeshTrianges);
        foreach (int idx in vertexIndexs_noRepeat)
        {
            float x = texRect.x + UVToZeroOne(tarUVList[idx].x) * texRect.width;
            float y = texRect.y + UVToZeroOne(tarUVList[idx].y) * texRect.height;
            if (idx == 0)
            {
                Debug.Log("idx="+idx+"  x="+x+"  old x="+ tarUVList[idx].x+ "  UVToZeroOne=" + UVToZeroOne(tarUVList[idx].x) + " texRect="+texRect.ToString());
            }
            tarUVList[idx] = new Vector2(x,y);
        }
    }
    public static float UVToZeroOne(float i)
    {
        float o = 0;
        o = i - Mathf.Floor(i);
        return o;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMesh(Mesh srcMesh)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【"+i+"】拥有三角形数量为【"+(srcSubmeshTriangeArray.Length/3)+"】顶点索引为【"+ ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【"+ ShowArrayElements(hadSharedVertexIndexArr) +"】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【"+ tarVertexList.Count+ "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i,hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList,ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【"+ ShowDictionary(vertexIndexRef)+ "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【"+ ShowArrayElements(newSubmeshTrianges)+ "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【"+i+"】循环结束,未更新三角形顶点索引为【"+ShowListElements(srcBeforCurrentSubmeshTrianges)+"】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_"+srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    /// <summary>
    /// 合并包含多个子网格的网格为只有一个子网格的网格
    /// </summary>
    /// <param name="srcMesh"></param>
    /// <returns></returns>
    public static Mesh MergeSubMeshStoreRect(Mesh srcMesh,Rect[] rects)
    {
        Mesh tarMesh = new Mesh();
        List<Vector3> tarVertexList = new List<Vector3>();//要构建的目标网格顶点列表
        List<Vector3> tarNormalList = new List<Vector3>();
        List<Vector2> tarUVList = new List<Vector2>();
        List<Vector2> tarUV2List = new List<Vector2>();
        List<Vector2> tarUV3List = new List<Vector2>();
        List<int> tarTrianges = new List<int>();//要构建的目标网格三角形列表

        List<Vector3> addVertexList = new List<Vector3>();//新添加的顶点列表
        List<Vector3> existInBeforCurrentSubmeshVL = new List<Vector3>();//当前子网格之前出现过的顶点列表
        List<Vector3> sharedInCurrentSubmeshVL = new List<Vector3>();//当前子网格与其他子网格共享的顶点列表

        Vector3[] srcVertexArray = srcMesh.vertices;
        Vector3[] srcNormalArray = srcMesh.normals;
        Vector2[] srcUvArray = srcMesh.uv;
        int[] srcTrianges = srcMesh.triangles;
        int srcSubmeshCount = srcMesh.subMeshCount;

        //初始化
        tarVertexList = initVertexOrNormalList(srcVertexArray);
        tarNormalList = initVertexOrNormalList(srcNormalArray);
        tarUVList = initUvList(srcUvArray);
        tarUV2List = initUvList(tarUVList.ToArray());
        tarUV3List = initUvList(tarUVList.ToArray());
        List<int> srcBeforCurrentSubmeshTrianges = new List<int>();
        for (int i = 0; i < srcSubmeshCount; i++)
        {
            int[] srcSubmeshTriangeArray = srcMesh.GetTriangles(i);

            Debug.Log("子网格【" + i + "】拥有三角形数量为【" + (srcSubmeshTriangeArray.Length / 3) + "】顶点索引为【" + ShowArrayElements(srcSubmeshTriangeArray) + "】");
            //找出当前子网格与前面的所有子网格共用的顶点列表。
            int[] hadSharedVertexIndexArr = ArrayFindSharedElements(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            Debug.Log("已共用顶点索引【" + ShowArrayElements(hadSharedVertexIndexArr) + "】");
            //复制共享顶点列表,添加顶点
            int[] oldSubmeshTrianges = CopyArray(srcSubmeshTriangeArray);
            int[] newSubmeshTrianges = oldSubmeshTrianges;
            if (hadSharedVertexIndexArr != null && hadSharedVertexIndexArr.Length > 0)
            {
                Debug.Log("添加顶点前:拥有顶点数【" + tarVertexList.Count + "】");
                Dictionary<int, int> vertexIndexRef = new Dictionary<int, int>();

                CopyAndAddVertexs(i, hadSharedVertexIndexArr, srcUvArray, ref tarVertexList, ref tarNormalList, ref tarUVList, ref tarUV2List, ref vertexIndexRef);
                Debug.Log("添加顶点后:拥有顶点数【" + tarVertexList.Count + "】,旧新顶点对应关系【" + ShowDictionary(vertexIndexRef) + "】");
                //通过旧新顶点索引对应关系更新三角形数组
                newSubmeshTrianges = UpdateTrianges(oldSubmeshTrianges, vertexIndexRef);
                Debug.Log("通过旧新顶点索引对应关系更新后的三角形顶点索引为【" + ShowArrayElements(newSubmeshTrianges) + "】");
            }
            //根据三角形顶点列表更新UV2,标识顶点来源自哪个子网格
            //UdateUv2(i, newSubmeshTrianges, ref tarUV2List);
            StoreRectToUV(newSubmeshTrianges, rects[i], ref tarUV2List, ref tarUV3List);
            //存储本此循环数据,为下一次循环作准备
            srcBeforCurrentSubmeshTrianges = MergeArrayToList(srcBeforCurrentSubmeshTrianges.ToArray(), srcSubmeshTriangeArray);
            tarTrianges = MergeArrayToList(tarTrianges.ToArray(), newSubmeshTrianges);
            Debug.Log("本次【" + i + "】循环结束,未更新三角形顶点索引为【" + ShowListElements(srcBeforCurrentSubmeshTrianges) + "】");
            Debug.Log("本次【" + i + "】循环结束,更新后三角形顶点索引为【" + ShowListElements(tarTrianges) + "】");
        }
        //组装新的网格
        tarMesh.name = "Msm_" + srcMesh.name;
        tarMesh.vertices = tarVertexList.ToArray();
        tarMesh.normals = tarNormalList.ToArray();
        tarMesh.uv = tarUVList.ToArray();
        tarMesh.uv2 = tarUV2List.ToArray();
        tarMesh.uv3 = tarUV3List.ToArray();
        tarMesh.triangles = tarTrianges.ToArray();
        return tarMesh;
    }
    public static void StoreRectToUV(int[] newSubmeshTrianges,Rect rect,ref List<Vector2> uv2,ref List<Vector2> uv3)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2(rect.x, rect.y);
                uv3[vIdx] = new Vector2(rect.width, rect.height);
            }
        }
    }
    public static void UdateUv2(int currSubmeshId, int[] newSubmeshTrianges, ref List<Vector2> uv2)
    {
        if (newSubmeshTrianges != null && newSubmeshTrianges.Length > 0)
        {
            foreach (int vIdx in newSubmeshTrianges)
            {
                uv2[vIdx] = new Vector2((float)currSubmeshId,0.0f);
            }
        }
        //Debug.Log("UV2="+ ShowUVs(uv2));
    }
    public static string ShowUVs(List<Vector2> uv2)
    {
        string rs = "";
        for(int i=0;i<uv2.Count; i++)
        {
            rs += i+"["+uv2[i].x+","+uv2[i].y+"] ";
        }
        return rs;
    }
    public static int[] UpdateTrianges(int[] oldTrianges,Dictionary<int,int> idxRef)
    {
        int[] newTrianges = new int[oldTrianges.Length];
        for (int i = 0; i < oldTrianges.Length; i++)
        {
            if (idxRef.ContainsKey(oldTrianges[i]))
            {
                newTrianges[i] = idxRef[oldTrianges[i]];
            }
            else
            {
                newTrianges[i] = oldTrianges[i];
            }
        }
        return newTrianges;
    }
    public static int[] CopyArray(int[] arr)
    {
        int[] o = new int[arr.Length];
        for (int i = 0; i < arr.Length; i++)
        {
            o[i] = arr[i];
        }
        return o;
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// </summary>
    /// <param name="vIndexArr"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int[] vIndexArr, Vector2[] srcUVList,
                                        ref List<Vector3> oldVextexList,
                                        ref List<Vector3> oldNormalList,
                                        ref List<Vector2> oldUVList,
                                        ref Dictionary<int,int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref List<Vector2> oldUV3List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh, 0.0f));
                oldUV3List.Add(new Vector2((float)currentSubmesh, 0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 按顶点索引复制并添加顶点【位置,法线,贴图坐标】,并记录旧顶点索引和新加顶点索引的对应关系(用来更新子网格三角形)
    /// 用第二套UV的U分量来存储子网格id,经过光栅化插值后,还是子网格id的值。用来标识片元来自哪个子网格,转换uv的时候对应用哪个Rect
    /// </summary>
    /// <param name="currentSubmesh"></param>
    /// <param name="vIndexArr"></param>
    /// <param name="srcUVList"></param>
    /// <param name="oldVextexList"></param>
    /// <param name="oldNormalList"></param>
    /// <param name="oldUVList"></param>
    /// <param name="vertexIndexRef"></param>
    public static void CopyAndAddVertexs(int currentSubmesh,
                                         int[] vIndexArr, Vector2[] srcUVList,
                                         ref List<Vector3> oldVextexList,
                                         ref List<Vector3> oldNormalList,
                                         ref List<Vector2> oldUVList,
                                         ref List<Vector2> oldUV2List,
                                         ref Dictionary<int, int> vertexIndexRef)
    {
        if (vIndexArr != null && vIndexArr.Length > 0)
        {
            foreach (int e in vIndexArr)
            {
                oldVextexList.Add(oldVextexList[e]);
                oldNormalList.Add(oldNormalList[e]);
                oldUVList.Add(srcUVList[e]);
                oldUV2List.Add(new Vector2((float)currentSubmesh,0.0f));
                vertexIndexRef.Add(e, oldVextexList.Count - 1);
            }
        }
    }
    /// <summary>
    /// 初始化顶点或法线列表
    /// </summary>
    /// <param name="srcVertexArray"></param>
    /// <returns></returns>
    public static List<Vector3> initVertexOrNormalList(Vector3[] srcVertexArray)
    {
        List<Vector3> vList = new List<Vector3>();
        if (!(srcVertexArray == null || srcVertexArray.Length == 0))
        {
            foreach (Vector3 e in srcVertexArray)
            {
                vList.Add(e);
            }
        }
        return vList;
    }
    /// <summary>
    /// 初始化UV列表
    /// </summary>
    /// <param name="srcUvArray"></param>
    /// <returns></returns>
    public static List<Vector2> initUvList(Vector2[] srcUvArray)
    {
        List<Vector2> uvList = new List<Vector2>();
        if (!(srcUvArray == null || srcUvArray.Length == 0))
        {
            foreach (Vector2 e in srcUvArray)
            {
                uvList.Add(e);
            }
        }
        return uvList;
    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] MergeArrayToArray(int[] arr1,int[] arr2)
    {
        if (arr1 == null || arr1.Length == 0)
        {
            return arr2;
        }
        else if (arr2 == null || arr2.Length == 0)
        {
            return arr1;
        }
        else
        {
            int[] mergeArr =new int[arr1.Length + arr2.Length];
            for (int i = 0; i < arr1.Length; i++)
            {
                mergeArr[i] = arr1[i];
            }
            for (int i = 0; i < arr2.Length; i++)
            {
                mergeArr[arr1.Length+i] = arr2[i];
            }
            return mergeArr;
        }

    }
    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static List<int> MergeArrayToList(int[] arr1, int[] arr2)
    {
        int[] arr = MergeArrayToArray(arr1,arr2);
        List<int> list = new List<int>();
        if (!(arr == null || arr.Length == 0))
        {
            foreach (int e in arr)
            {
                list.Add(e);
            }
        }
        return list;
    }
    /// <summary>
    /// 去除数组中的重复元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static List<int> ArrayRemoveDuplication(int [] arr)
    {
        List<int> list = new List<int>();
        foreach (int i in arr)
        {
            if (!list.Contains(i))
            {
                list.Add(i);
            }
        }
        return list;
    }
    /// <summary>
    /// 找出数组2在数组1中已包含的元素
    /// </summary>
    /// <param name="arr1"></param>
    /// <param name="arr2"></param>
    /// <returns></returns>
    public static int[] ArrayFindSharedElements(int[] arr1, int[] arr2)
    {
        List<int> list1_noRepeat = ArrayRemoveDuplication(arr1);
        List<int> list2_noRepeat = ArrayRemoveDuplication(arr2);
        List<int> comm = new List<int>();
        foreach (int e in list2_noRepeat)
        {
            if (list1_noRepeat.Contains(e))
            {
                comm.Add(e);
            }
        }
        return comm.ToArray();
    }
    /// <summary>
    /// 显示数组元素
    /// </summary>
    /// <param name="arr"></param>
    /// <returns></returns>
    public static string ShowArrayElements(int[] arr)
    {
        string rs = "[";
        foreach(int i in arr)
        {
            rs += i + " ";
        }
        return rs+"]";
    }
    public static string ShowListElements(List<int> list)
    {
        return ShowArrayElements(list.ToArray());
    }
    public static string ShowDictionary(Dictionary<int,int> dic)
    {
        string rs = "";
        foreach (int k in dic.Keys)
        {
            rs += k + "-->" + dic[k] + "|";
        }
        return rs;
    }
}


Shader "6/Room_Ruin_2_Opaque"
{
       Properties
       {
              _MainTex("Abedo", 2D) = "white" {}
       _Color("Abedo Color",Color) = (1,1,1,1)
              //_AlphaTex("Alpha",2D) = ""{}
              //_AlphaScale("Alpha Scale",Range(0.0,1.0))=1.0
              _NormalTex("Normal",2D) = "bump"{}
       _BumpScale("Normal/Bump Scale",Range(0.0,3.0)) = 1.0
              [Header(specular)]
       _Specular("Specular",Color) = (1,1,1,1)
              _Gloss("Gloss",Range(8,256)) = 20
              [Header(light mode weights)]
       _AmbientWeight("Ambient Weight",Range(0.0,1.0)) = 1.0
              _DiffuseWeight("Diffuse Weight",Range(0.0,1.0)) = 1.0
              _SpecularWeight("Specular Weight",Range(0.0,1.0)) = 1.0
       }
              SubShader
       {
              Tags{ "RenderType" = "Opaque" }
              LOD 100
              Pass
       {
              Tags{ "LightMode" = "ForwardBase" }
              CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase     
#include "Lighting.cginc"
#include "AutoLight.cginc"
              struct appdata
       {
              float4 vertex : POSITION;
              float3 normal:NORMAL;
              float4 tangent:TANGENT;
              float2 uv : TEXCOORD0;
              //float2 uv2 : TEXCOORD1;
       };
       struct v2f
       {
              float4 pos : SV_POSITION;
              float2 uv : TEXCOORD0;
              float3 tengentLightDir:TEXCOORD1;
              float3 tangentViewDir:TEXCOORD2;
              SHADOW_COORDS(3)
       };
       sampler2D _MainTex;
       float4 _MainTex_ST;
       half4 _MainTex_TexelSize;
       //float4  _TexRect[8];
       fixed4 _Color;
       //sampler2D _AlphaTex;
       //float4 _AlphaTex_ST;
       //fixed _AlphaScale;
       sampler2D _NormalTex;
       float4 _NormalTex_ST;
       half _BumpScale;
       //specular
       fixed4 _Specular;
       half _Gloss;
       //light mode weights
       fixed _AmbientWeight;
       fixed _DiffuseWeight;
       fixed _SpecularWeight;
       v2f vert(appdata v)
       {
              v2f o;
              o.pos = UnityObjectToClipPos(v.vertex);
              o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
              //o.uv.z = v.uv2.x;
              TANGENT_SPACE_ROTATION;
              o.tengentLightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
              o.tangentViewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
              TRANSFER_SHADOW(o);
              return o;
       }
       fixed4 frag(v2f i) : SV_Target
       {
              fixed3 tangentLightDir = normalize(i.tengentLightDir);
       fixed3 tangentViewDir = normalize(i.tangentViewDir);
       fixed4 packedNormal = tex2D(_NormalTex, i.uv);
       fixed3 tangentNormal = UnpackNormal(packedNormal);
       tangentNormal.xy *= _BumpScale;
       tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
       
       //int idx = (int)(i.uv.z+0.0001);
       //float4 rect = _TexRect[idx].xyzw;
       //fixed2 uv = i.uv.xy - floor(i.uv.xy);
       //float u = i.uv.x - floor(i.uv.x) + 0.0001;
       //float u = frac(i.uv.x);
       //u = rect.x + u*rect.z;
       //float v = i.uv.y - floor(i.uv.y) + _MainTex_TexelSize.y*100;
       //float v = frac(i.uv.y);
       //v = rect.y + v*rect.w;
       fixed3 abedo = tex2D(_MainTex, i.uv).rgb*_Color.rgb;
       return fixed4(abedo,1);
       //
       ////light mode
       //fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*abedo*_AmbientWeight;
       //fixed3 diffuse = _LightColor0.rgb*abedo*saturate(dot(tangentNormal, tangentLightDir))*_DiffuseWeight;
       //fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(tangentNormal, normalize(tangentLightDir + tangentViewDir))), _Gloss)*_SpecularWeight;
       //fixed atten = SHADOW_ATTENUATION(i);
       //return fixed4(ambient + (diffuse + specular)*atten,1);
       }
              ENDCG
       }
       }
              Fallback "Diffuse"
}

展开阅读全文

没有更多推荐了,返回首页