概述
2D專案使用Sprite和其他圖形來建立其場景的視覺效果。這意味著單個專案可能包含許多紋理檔案。Unity 通常會為場景中的每個紋理髮出一個DrawCall;但是,在具有許多紋理的專案中,多個繪製呼叫會佔用大量資源,並會對專案的效能產生負面影響。
精靈圖集 (Sprite Atlas) 是一種將多個紋理合併為一個組合紋理的資源。Unity 可以呼叫此單個紋理來發出單個繪製呼叫而不是發出多個繪製呼叫,能夠以較小的效能開銷一次性訪問壓縮的紋理。
為什麼圖集可以減少DrawCall
簡單點說就是:使用圖集,我們就可以歸類不同種類的圖片,之後就可以一次進行多張圖片的繪製處理,只需呼叫一次DC,提高了效率。
什麼是DrawCall
DrawCall就是一個命令(也是CPU呼叫圖形程式設計介面,比如DirectX或OpenGL),一個由CPU發起,命令GPU執行的命令,就是CPU告訴GPU可以對某個模型進行渲染處理的傳話人。一般來說一個獨立的模型會產生一個DrawCall,但是如果經過一些特殊的處理,比如動態合批,靜態合批等等操作,就會降低DrawCall。
為什麼DrawCall會影響CPU效能
CPU將DrawCall發往GPU過程中並不是很直接的就交給GPU,而是先將這些資料存到一個命令緩衝區內,然後再後面的幾何階段由GPU進行資料的讀取。GPU的渲染能力是很強的,渲染300個和3000個三角網格通常沒有什麼區別,因此渲染速度往往快於CPU提交命令的速度。DrawCall的數量太多,CPU就會把大量時間花費在提交DrawCall命令上,造成CPU的過載。
為什麼圖集的大小要設成2的N次方
因為大部分遊戲引擎底層的渲染方式都是基於OpenGL的,OpenGL載入紋理圖片時,所用記憶體會自動擴張到2的N次方(500 x 500 → 512 x 512)。
- 因為轉化過程比較慢,由執行程式轉換十分耗時,所以Unity3D提前將資源轉化為符合標準的圖片,這樣可以提升轉化速度;
- 節省記憶體。一張圖片的大小為1010畫素,OpenGL會按照1616的規格將圖片載入到記憶體中;如果圖片大小為6465,那麼就會按照64128載入了,這就造成了記憶體的無必要開銷;
- 減少包體。打成圖集後的合成的大圖會比之前所有的散圖所佔用的物理儲存更小。這樣從透過減小圖片資源物理儲存大小起到壓縮遊戲安裝包的作用。
圖集的壓縮格式
為什麼要壓縮
- 我們平時看到的圖片一般都是png、jpg、bmp等格式的。在實際開發中,我們一般是不會直接用這些格式,因為載入速度慢,佔用記憶體高;
- 為什麼這麼說呢?因為這些壓縮格式不是硬體支援的,所以需要在記憶體中解壓後再傳給GPU用,那解壓後的記憶體有多大呢?假設一張有4通道的1024*1024的圖片,每通道8位的話,那這一張圖就是4M,如果是RGBA4444的話也有2M;
- 那還有什麼壓縮格式可用呢?很多,比如安卓支援ETC格式、IOS支援PVRTC格式,還有ASTC格式。我們以ETC2 8bits為例,同樣一張有4通道的1024*1024的圖片,一個畫素佔1個位元組,所以就佔1M。 比前面省了4倍;
- PVRTC 4bits壓縮更高,最後大小也就0.5M;
- 如果用PVRTC 2bits,還能更小,但壓縮質量會有所下降;
- 請注意,PVRTC 格式要求紋理為正方形(即寬度等於高度);
- 上述格式除了壓縮率高,還是硬體直接支援的,不需要解壓。無論載入速度還是記憶體佔用上表現都非常不錯。
壓縮格式該怎麼選擇
- 壓縮格式之所以這麼多就是因為硬體太多了,大家都為了解決效能的問題,所以整出了這麼多格式;
- 至於怎麼選擇,我們粗略的給出了答案。安卓選擇ETC格式,不帶透明度的可以用ETC1,帶透明度的用ETC2。IOS選擇PVRTC格式;
- 如果要用ASTC的話,需要達到一定的條件,如下:Android:需要 GL_KHR_texture_compression_astc_hdr 擴充套件。iOS:需要 A13 或更高版本的晶片 (2019)。如果不支援,則紋理將解壓縮為 RGB9E5 格式,從而失去了 Alpha 通道。
圖集的缺點
在使用圖集時,會將整張圖集載入進記憶體,因此應當將經常需要顯示的圖片素材放到同一張圖集中,如果不經常使用的也放到同一張圖集,即使這張圖片不需要顯示,也會被載入進記憶體彙總。同時圖集的大小固定為POT(Power of Two),如果圖集中的元素大小差距過大,也會導致空間浪費。