轉自:http://blog.csdn.net/ecidevilin/article/details/52490960
合併網格可以提升性能,而且也可以讓我們更好更靈活的管理模型。
例如下面這三個模型:
有些時候我們會希望這三個模型使用同一個Collider,但是我們顯然不能讓美術再給我們專門爲碰撞做模型來。因爲他們可能會有不同的組合,或者跟其他的物體進行組合,如果每種組合都做一個碰撞模型的話,美術大人會砍死我們的,而且這樣也不利於維護(調整一下座標,這個碰撞模型就得重做)。
那麼只有我們程序來實現了。
這裏我們用到了Untiy的一個API——CombineMeshes。
CombineMeshes有三個參數:
combine:CombineInstance(struct)類型的數組,這個結構裏包括了需要合併的網格(mesh),子網格的索引(subMeshIndex)和轉換矩陣(transform)。
mergeSubMeshes:bool值,是否需要將所有的Mesh合併成一個。
useMatrices:bool值,是否使用矩陣,如果爲false,那麼CombineInstance裏的transform將會被忽略。
那麼我們來實現這樣一個功能。
我們選取圖中某個對象做爲父對象,將其他兩個對象作爲它的子對象。
並新建一個腳本,添加到父對象上。腳本如下:
- using UnityEngine;
- using System.Collections;
- [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
- public class CombineMesh : MonoBehaviour {
- void Start()
- {
- MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter> ();
- CombineInstance[] combine = new CombineInstance[meshFilters.Length];
- Material[] mats = new Material[meshFilters.Length];
- Matrix4x4 matrix = transform.worldToLocalMatrix;
- for (int i = 0; i < meshFilters.Length; i++) {
- MeshFilter mf = meshFilters [i];
- MeshRenderer mr = meshFilters [i].GetComponent<MeshRenderer> ();
- if (mr == null) {
- continue;
- }
- combine[i].mesh = mf.sharedMesh;
- combine[i].transform = mf.transform.localToWorldMatrix * matrix;
- mr.enabled = false;
- mats [i] = mr.sharedMaterial;
- }
- MeshFilter thisMeshFilter = GetComponent<MeshFilter> ();
- Mesh mesh = new Mesh ();
- mesh.name = "Combined";
- thisMeshFilter.mesh = mesh;
- mesh.CombineMeshes (combine, false);
- MeshRenderer thisMeshRenderer = GetComponent<MeshRenderer> ();
- thisMeshRenderer.sharedMaterials = mats;
- thisMeshRenderer.enabled = true;
- MeshCollider thisMeshCollider = GetComponent<MeshCollider> ();
- if (thisMeshCollider != null) {
- thisMeshCollider.sharedMesh = mesh;
- }
- }
- }
腳本里我們做了幾件事情:
1、將MeshFilter裏的sharedMesh保存給CombineInstance。
2、計算transform矩陣,將子對象(或本對象)本地轉世界的矩陣和本對象世界轉本地的矩陣相乘,就得到了子對象(或本對象)轉換到本對象本地的矩陣。
3、將MeshRenderer的sharedMaterial保存到數組裏(關於sharedMaterial可以參考我之前的文章)。並且將MeshRenderer設置爲不可用的,這樣子對象就不會再渲染了。如果這裏換成gameObject.SetActive(false)是不恰當的,因爲那樣的話,gameObject上掛載的其他組件也不能執行。
4、新建一個mesh,賦給MeshFilter,並調用CombineMesh的方法合併子mesh。因爲我們要用不同的Material,所以第二個參數mergeSubMeshes爲false。(順口一提,如果第三個參數useMatrices爲false的話,所有mesh都會從local原點開始)
5、將Material數組賦值給MeshRenderer的sharedMaterials,並將MeshRenderer設置爲可用的。
6、最後判斷如果存在MeshCollider,將MeshCollider的sharedMesh賦值爲新建的mesh。
最後要補充一點,如果本對象和所有子對象都是用相同的材質和紋理的話,那麼這段代碼就需要修改一下,把Material相關的代碼去掉即可,然後CombineMesh的第二個參數要改爲true(默認true)。當然,添加一個public的bool變量來控制是否使用同一個Material的話也是不錯的選擇。
附上可用的代碼下載鏈接。