如需转载请注明出处
最近项目中由于场景中的小物件比较多导致在进入场景的时候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