Unity3D Mesh小課堂(五)CombineMeshes合併網格

轉自:http://blog.csdn.net/ecidevilin/article/details/52490960

合併網格可以提升性能,而且也可以讓我們更好更靈活的管理模型。

例如下面這三個模型:


有些時候我們會希望這三個模型使用同一個Collider,但是我們顯然不能讓美術再給我們專門爲碰撞做模型來。因爲他們可能會有不同的組合,或者跟其他的物體進行組合,如果每種組合都做一個碰撞模型的話,美術大人會砍死我們的,而且這樣也不利於維護(調整一下座標,這個碰撞模型就得重做)。

那麼只有我們程序來實現了。

這裏我們用到了Untiy的一個API——CombineMeshes

CombineMeshes有三個參數:

combine:CombineInstancestruct)類型的數組,這個結構裏包括了需要合併的網格(mesh),子網格的索引(subMeshIndex)和轉換矩陣(transform)。

mergeSubMeshes:bool值,是否需要將所有的Mesh合併成一個。

useMatrices:bool值,是否使用矩陣,如果爲false,那麼CombineInstance裏的transform將會被忽略。

那麼我們來實現這樣一個功能。

我們選取圖中某個對象做爲父對象,將其他兩個對象作爲它的子對象。

並新建一個腳本,添加到父對象上。腳本如下:

[csharp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]  
  5. public class CombineMesh : MonoBehaviour {  
  6.   
  7.     void Start()  
  8.     {  
  9.         MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter> ();  
  10.         CombineInstance[] combine = new CombineInstance[meshFilters.Length];  
  11.         Material[] mats = new Material[meshFilters.Length];  
  12.         Matrix4x4 matrix = transform.worldToLocalMatrix;  
  13.         for (int i = 0; i < meshFilters.Length; i++) {  
  14.             MeshFilter mf = meshFilters [i];  
  15.             MeshRenderer mr = meshFilters [i].GetComponent<MeshRenderer> ();  
  16.             if (mr == null) {  
  17.                 continue;  
  18.             }  
  19.             combine[i].mesh = mf.sharedMesh;  
  20.             combine[i].transform = mf.transform.localToWorldMatrix * matrix;  
  21.             mr.enabled = false;  
  22.             mats [i] = mr.sharedMaterial;  
  23.         }  
  24.         MeshFilter thisMeshFilter = GetComponent<MeshFilter> ();  
  25.         Mesh mesh = new Mesh ();  
  26.         mesh.name = "Combined";  
  27.         thisMeshFilter.mesh = mesh;  
  28.         mesh.CombineMeshes (combine, false);  
  29.         MeshRenderer thisMeshRenderer = GetComponent<MeshRenderer> ();  
  30.         thisMeshRenderer.sharedMaterials = mats;  
  31.         thisMeshRenderer.enabled = true;  
  32.   
  33.         MeshCollider thisMeshCollider = GetComponent<MeshCollider> ();  
  34.         if (thisMeshCollider != null) {  
  35.             thisMeshCollider.sharedMesh = mesh;  
  36.         }  
  37.   
  38.     }  
  39. }  

腳本里我們做了幾件事情:

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的話也是不錯的選擇。

附上可用的代碼下載鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章