1. 程式人生 > >Unity合併網格和貼圖

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