Unity合并网格和贴图

如需转载请注明出处


最近项目中由于场景中的小物件比较多导致在进入场景的时候DrawCall数量明显升高,所以就需要针对场景中的小物件进行网格的合并与贴图的合并,下面是贴图与网格合并的代码,更详细的逻辑需要根据需要去补充,如:搜索场景中的应用了这些贴图的GameObject。

private static void CombineTex_Mesh()
    {
        List<Texture2D> textures    =   new List<Texture2D>();
        string[]rGuids              =   AssetDatabase.FindAssets("t:Texture2D", new string[] { texPath });
        for (int guid = 0; guid < rGuids.Length; guid++)
        {
            string assetPath    = AssetDatabase.GUIDToAssetPath(rGuids[guid]);
            Texture2D rTex      = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath) as Texture2D;
            textures.Add(rTex);
        }
        if (textures.Count > 0)
        {
            Texture2D tempTex   = new Texture2D(2048, 2048);
            Rect[]uvs           = tempTex.PackTextures(textures.ToArray(), 0);
            tempTex.Apply();
            Texture2D rCombineTex = new Texture2D(tempTex.width, tempTex.height, TextureFormat.ARGB32, false);
            rCombineTex.SetPixels32(tempTex.GetPixels32());
            rCombineTex.Apply();
            byte[] bytes = rCombineTex.EncodeToPNG();
            File.WriteAllBytes(combindPath + "/combineTex.png", bytes);
            AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);
            rCombineTex = AssetDatabase.LoadAssetAtPath<Texture2D>(combindPath + "/combineTex.png");
            CombineMesh(SceneManager.GetSceneByName("Combine"), textures.ToArray(), rCombineTex ,uvs);
        }
    }
 
 
 
 private static void CombineMesh(Scene scene, Texture2D[] texs, Texture2D mainTexture, Rect[] rect)
    {
        GameObject combineGo = new GameObject("combineGo");
        GameObject[] allGameObjects = scene.GetRootGameObjects();
        List<Vector2[]> usList = new List<Vector2[]>();
        List<Color> colorList = new List<Color>();
        Color color = new Color();
        for (int object_index = 0; object_index < allGameObjects.Length; object_index++)
        {
            if (allGameObjects[object_index].name.Equals("CombineMesh"))
            {
                MeshFilter[] allFilter = allGameObjects[object_index].GetComponentsInChildren<MeshFilter>();
                MeshRenderer[] allRender = allGameObjects[object_index].GetComponentsInChildren<MeshRenderer>();
                CombineInstance[] combineMesh = new CombineInstance[allFilter.Length];
                Material[] materials = new Material[allFilter.Length];

                for (int i = 0; i < allFilter.Length; i++)
                {
                    materials[i] = allRender[i].sharedMaterial;
                    combineMesh[i].mesh = allFilter[i].sharedMesh;
                    combineMesh[i].transform = allFilter[i].transform.localToWorldMatrix;
                    usList.Add(allFilter[i].sharedMesh.uv);
                }
                MeshFilter combineFilter = combineGo.AddComponent<MeshFilter>();
                MeshRenderer combineRender = combineGo.AddComponent<MeshRenderer>();
                combineFilter.sharedMesh = new Mesh();
                combineFilter.sharedMesh.CombineMeshes(combineMesh);
                Vector2[] uv = new Vector2[combineFilter.sharedMesh.vertices.Length];

                int count = 0;
                for (int i = 0; i < usList.Count; i++)
                {
                    for (int filter_index = 0; filter_index < allFilter.Length; filter_index++)
                    {
                        float scaleX = ((float)(texs[filter_index].width) / mainTexture.width);
                        float scaleY = ((float)(texs[filter_index].height) / mainTexture.height);
                        for (int j = 0; j < allFilter[filter_index].sharedMesh.vertices.Length; j++)
                        {
                            uv[count] = new Vector2((float)(rect[filter_index].xMin + allFilter[filter_index].sharedMesh.uv[j].x * scaleX),
                                (float)(rect[filter_index].yMin + allFilter[filter_index].sharedMesh.uv[j].y * scaleY));
                            count++;
                        }
                    }
                    combineFilter.sharedMesh.uv = uv;
                    combineRender.sharedMaterials = materials;
                    combineRender.sharedMaterial.mainTexture = mainTexture;
                    AssetDatabase.CreateAsset(combineRender.sharedMaterial, combindPath + "/material.mat");
                    AssetDatabase.CreateAsset(combineFilter.sharedMesh, combindPath + "/mesh.asset");
                    combineGo.transform.SetParent(allGameObjects[object_index].transform);
                }
            }

 
 
 以上这两个函数就能达到基本的合并贴图与网格的效果,但是需要注意的一点是合并贴图使用的是Unity自带的texture.packtextures这个函数,这个函数虽然可以控制合并后贴图的大小,但是不会对需要合并的贴图能否刚好合并到一起且不压缩做检测,如果合并的贴图太多的话就会导致纹理UV错乱,所以在项目中我使用的是NGUI的贴图合并函数。Ngui的UITexturePacker这个类就是用来进行贴图合并的,你们可以调用它的PackTextures方法,这个方法还可以强制把合并后的贴图大小设置为2的N次方幂。虽然合并了网格与贴图会减少drawcall的数量,但是也会导致内存的上升,所以具体如果取舍还是需要看项目中的需求。 
 





最近项目中

asd 

猜你喜欢

转载自blog.csdn.net/tc3819171/article/details/60467290
今日推荐