Unity合併網格和貼圖
阿新 • • 發佈:2019-01-04
如需轉載請註明出處
最近專案中由於場景中的小物件比較多導致在進入場景的時候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