最近和朋友聊天,談到了Mesh的內存優化問題,他發現開啓Model Importer面板上的Mesh Compression選項以後,內存並無什麼變化。事實上,指望開啓Mesh Compression後Mesh所佔用的內存下降,是對Mesh Compression的做用的誤解。算法
我相信不少同窗看到Mesh Compression這個名字以後,也會有相似的誤解。所以這篇博客就來聊一聊在Unity中如何對Mesh進行優化,以達到節約內存的目的,而且爲什麼開啓了Mesh Compression選項反而對內存沒有什麼幫助。ide
在Unity中,主要有三種方式用來優化mesh數據的空間開銷。測試
即Player Setting中的:優化
Vertex Compressionui
Optimize Mesh Data3d
以及Model importer中的:orm
Mesh Compression blog
其中,Vertex Compression的實現是將頂點channel的數據格式format設置爲16bit,所以能夠節約運行時的內存使用(float->half)。內存
Optimize Mesh Data則主要用來剔除不須要的channel,即剔除額外的數據。由於與壓縮無關,本文先暫時不討論這個選項。博客
可是,Mesh Compression是使用壓縮算法,將mesh數據進行壓縮,結果是會減小佔用硬盤的空間,可是在runtime的時候會被解壓爲原始精度的數據。
和Runtime時內存關係較大的是Vertex Compression的實現。
而是否能夠進行Vertex Compression,則和模型的導入設置以及是否能夠進行dynamic batching(在build 階段,主要判斷mesh的頂點數是否符合條件)有關。
簡單能夠概括爲如下幾點:
1. 是否適合進行dynamic batching
2. 在Model Importer中是否開啓了Read/Write Enabled
3. 在Model Importer中是否開啓了Mesh Compression(是的,很吃驚是吧)
其中第一點,就是該mesh是否適合進行dynamic batching。這裏不只和player setting中是否勾選了dynamic batching有關,還和mesh的頂點數是否超過300有關。固然,dynamic batching是否可行主要和頂點屬性的數量有關,可是爲了簡單,build階段就按照常見的一個頂點帶3個頂點屬性,也就是300個頂點來作限制了。
因此若是開啓了dynamic batching,則300個頂點如下的mesh不會被執行頂點壓縮。
其次,Read/Write Enabled這個選項也會使Vertex Compression失效。因此通常狀況下,爲了節約內存最好很差勾選這個選項,除了沒法進行頂點壓縮以外,它還會額外在內存中保留一份mesh數據。
再次,也是你們經常忽略的一點,即若是開啓了Mesh Compression,則會override掉Vertex Compression以及Optimize Mesh Data的設置 。Mesh Compression會將mesh在硬盤上的存儲空間進行壓縮,可是不會在runtime時節省內存。
下面咱們就經過幾個小例子,來直觀地查看一下各類設置下Mesh的內存佔用狀況。
Unity Version 2018.2.1
Windows Player
默認狀況,不開啓壓縮(MeshCompression和vertex compression),不開啓Read/Write Enabled
Model Importer:
Building_e:
MeshCompression Off
Read/Write Enabled Off
Rock_c:
MeshCompression Off
Read/Write Enabled Off
Player Setting:
Dynamic Batching Off
vertex compression:None
Optimize Mesh Data:Off
測試結果:
Building_e 0.5mb
Rock_c 3.3kb
題外話:若是開啓了Dynamic Batching,則Rock_c這個模型即使不開啓Read/Write Enabled,其的內存佔用也會更多,會達到5.9kb,這是由於對於頂點數較少(300如下)的模型,在開啓動態合批的狀況下咱們會多保留一份它的mesh數據,即和Read/Write Enabled開啓的效果是同樣的。
測試只開啓vertex compression的狀況。
Model Importer:
Building_e:
MeshCompression Off
Read/Write Enabled Off
Rock_c:
MeshCompression Off
Read/Write Enabled Off
Player Setting:
Dynamic Batching Off
vertex compression:Everything
Optimize Mesh Data:Off
測試結果:
Building_e 379.8kb
Rock_c 2.6kb
此時壓縮生效。
測試開啓vertex compression 和 dynamic batching 的狀況。
Model Importer:
Building_e:
MeshCompression Off
Read/Write Enabled Off
Rock_c:
MeshCompression Off
Read/Write Enabled Off
Player Setting:
Dynamic Batching On
vertex compression:Everything
Optimize Mesh Data:Off
測試結果:
Building_e 379.8kb
Rock_c 5.9kb
能夠看到,Rock_c的內存佔用升高了。這是由於Rock_c的頂點數只有40+,而且index buffer的format是16bit,在開啓dynamic batching的狀況下Build時被認爲是符合動態合批條件的,所以在構建時不會執行vertex compression的操做。
所以在開啓動態合批時,對一些小模型(vertex count<300)Vertex Compression是無效的。而且,這樣的模型一樣會保留在cpu可訪問的內存中,以備動態合批的須要。
測試開啓vertex compression 和 dynamic batching 以及Read/Write Enabled的狀況。
Model Importer:
Building_e:
MeshCompression Off
Read/Write Enabled On
Rock_c:
MeshCompression Off
Read/Write Enabled On
Player Setting:
Dynamic Batching On
vertex compression:Everything
Optimize Mesh Data:Off
測試結果:
Building_e 1.0mb
Rock_c 5.9kb
能夠看到,此時Building_e的內存不只沒有被壓縮變小,反而因爲開啓了Read/Write Enable而翻倍了。而Rock_c因爲以前說過的緣由,顯示的也是翻倍後的內存佔用。
因此,爲了保證vertex compression可以正常的執行,減少runtime時mesh的內存佔用,不要開啓 Read/Write Enable。
測試開啓vertex compression 和 dynamic batching 以及Mesh Compression的狀況。
我想最讓人迷惑的可能就是Mesh Compression這個選項。從字面理解,這個選項的開啓是對模型進行壓縮的意思。可是實際上開啓這個選項只會減少mesh在硬盤的存儲大小,在runtime時vertex使用format並無被改變,仍然是Float。所以也就沒法實現Runtime時內存的優化。
Model Importer:
Building_e:
MeshCompression On
Read/Write Enabled Off
Rock_c:
MeshCompression On
Read/Write Enabled Off
Player Setting:
Dynamic Batching On
vertex compression:Everything
Optimize Mesh Data:Off
測試結果:
Building_e 0.5mb
Rock_c 5.9kb
讓人吃驚的來了,Vertex Compression失效了。開啓了Mesh Compression以後,內存回到了沒有壓縮時的數值。
之因此勾選Mesh Compression後會有這個結果的緣由,在上文已經描述了不少。
所以,一個小建議就是若是爲了優化Mesh的內存開銷,不要開啓Mesh Compression,以免Vertex Compression的失效。