楊曉虎 朱穎 朱珣
摘? 要:在傳統(tǒng)游戲開發(fā)的過程中,圖形渲染上的優(yōu)化一直是一個(gè)難題,在Unity中最常用的優(yōu)化方法就在于減少DrawCall,一次DrawCall就是CPU準(zhǔn)備數(shù)據(jù)并通知GPU繪制圖形的過程。當(dāng)DrawCall數(shù)量過多時(shí),就會(huì)導(dǎo)致CPU大量計(jì)算進(jìn)而導(dǎo)致CPU過載,影響游戲運(yùn)行效率。而在Unity中,最有效的優(yōu)化DrawCall的方法就是批處理,Unity中的批處理分為動(dòng)態(tài)批處理和靜態(tài)批處理。同時(shí),兩種批處理的效率和適用范圍也不一樣。可以通過Unity的Stats面板信息,觀察實(shí)際批處理對(duì)DrawCall數(shù)量的影響。對(duì)于動(dòng)態(tài)批處理來說,優(yōu)點(diǎn)是一切處理Unity自動(dòng)完成的,不需要做任何操作,而且物體可以移動(dòng),缺點(diǎn)是限制很多。而對(duì)于靜態(tài)批處理來說,它的優(yōu)點(diǎn)是自由度很高,限制很少;但缺點(diǎn)是可能會(huì)占用更多的內(nèi)存,而經(jīng)過靜態(tài)批處理后的所有物體都不可以再移動(dòng)。
關(guān)鍵詞:Unity3D;動(dòng)態(tài)批處理;靜態(tài)批處理;DrawCall
中圖分類號(hào):TP317? ? ? ? ?文獻(xiàn)標(biāo)志碼:A? ? ? ? ?文章編號(hào):2095-2945(2020)03-0031-02
Abstract: In the process of traditional game development, the optimization of graphics rendering has always been a problem. The most commonly used optimization method in unity is to reduce the number of drawcalls, which is the process of CPU preparing data and informing GPU to draw graphics. When the number of drawcalls is too large, it will lead to a large number of CPU calculations, which will lead to CPU overload and affect the efficiency of the game. In unity, the most effective way to optimize drawcall is batch processing, which is divided into dynamic batching and static batching. At the same time, the efficiency and scope of application of the two batching are different. One can use the stats panel information of unity to observe the impact of the actual batching on the number of drawcalls. For dynamic batching, the advantage is that all processing is done automatically without any operation, and the object can be moved. The disadvantage is that there are many limitations. For static batching, it has the advantages of high degree of freedom and few restrictions, but it may occupy more memory, and after static batch processing, all objects can no longer be moved.
Keywords: Unity3D; dynamic batching; static batching; DrawCall
Unity3D中渲染優(yōu)化——批處理技術(shù)
1 批處理
下Unity3D在屏幕上繪制一個(gè)圖形本質(zhì)是調(diào)用OpenGL或者DirectX這樣的外部接口,因此在這個(gè)過程中會(huì)產(chǎn)生一定程度上的性能消耗。DrawCall是OpenGL中描述繪制次數(shù)的一個(gè)量。一個(gè)基本的OpenGL繪制流程是(1)設(shè)置顏色;(2)繪圖方式;(3)頂點(diǎn)坐標(biāo);(4)繪制,在繪制的過程中每幀都會(huì)重復(fù)這個(gè)過程,這就是一次DrawCall,所以當(dāng)游戲中的繪制過程變得復(fù)雜的時(shí)候,就會(huì)帶來DrawCall的急劇增加,進(jìn)而帶來游戲的性能問題,反映到游戲表現(xiàn)上就變成了優(yōu)化問題。在Unity3D使用了批處理來達(dá)到降低DrawCall的目的,批處理希望通過對(duì)物體網(wǎng)格的重組來獲得更高的繪制效率。在Uniyu3D中支持兩種類型的批處理,分為動(dòng)態(tài)批處理和靜態(tài)批處理。
2 材質(zhì)影響
只有用相同材質(zhì)的物體才可以進(jìn)行批處理,因此,在程序中盡可能地復(fù)用材質(zhì),就能在批處理時(shí)減少更多的DrawCall。如果物體的兩個(gè)材質(zhì)僅僅是紋理不相同,那么可以通過紋理拼合來將這兩張紋理合成一張大的紋理,合成后的單一材質(zhì)可以用來替代之前的兩個(gè)材質(zhì)。值得注意的是,在程序中應(yīng)該使用Renderer.sharedMaterial來保證材質(zhì)的共享狀態(tài),因?yàn)楦淖僐enderer.material會(huì)造成一份材質(zhì)的拷貝,從而導(dǎo)致物體的原材質(zhì)沒有被合并。
3 動(dòng)態(tài)批處理
動(dòng)態(tài)批處理的實(shí)現(xiàn)原理是:合并每一幀可以進(jìn)行批處理的模型網(wǎng)格,再將合并后的模型數(shù)據(jù)傳遞給GPU,然后使用同一個(gè)材質(zhì)對(duì)其渲染,動(dòng)態(tài)批處理的優(yōu)點(diǎn)在于一切處理由Unity3D自動(dòng)完成,實(shí)現(xiàn)方便,同時(shí)經(jīng)過批處理的物體仍然可以發(fā)生位置上的移動(dòng)。
動(dòng)態(tài)批處理只有對(duì)滿足條件的模型和材質(zhì)才可以被動(dòng)態(tài)批處理。所以動(dòng)態(tài)批處理存在一些條件上的限制。
(1)動(dòng)態(tài)批處理網(wǎng)格的頂點(diǎn)屬性規(guī)模要小于一個(gè)數(shù)值,該數(shù)值在最新版Unity2019.2中為900。針對(duì)此條限制,優(yōu)化策略就是對(duì)shader的優(yōu)化,盡量少使用頂點(diǎn)屬性,或者模型頂點(diǎn)數(shù)要盡可能的少。
(2)有多個(gè)Pass通道的Shader會(huì)中斷批處理。例如在前向渲染的過程中,使用額外的Pass來為模型添加更多的光照效果,但這樣一來模型就不會(huì)被動(dòng)態(tài)批處理。
(3)需要謹(jǐn)慎處理使用了光照貼圖紋理的物體。例如,在光照貼圖紋理上的索引和偏移量以及縮放信息等。因此,為了讓這些物體可以被動(dòng)態(tài)批處理,需要保證它們指向光照貼圖紋理中的同一個(gè)位置。
4 靜態(tài)批處理
靜態(tài)批處理的實(shí)現(xiàn)原理是,只有在運(yùn)行的開始階段,把需要進(jìn)行靜態(tài)批處理的模型合并到一個(gè)新的網(wǎng)格結(jié)構(gòu)中。因此,靜態(tài)批處理的模型在運(yùn)行時(shí)無法移動(dòng)。同時(shí)由于合并操作只需要進(jìn)行一次,靜態(tài)批處理的優(yōu)化效率比動(dòng)態(tài)批處理更高。靜態(tài)批處理是利用“空間”換“時(shí)間”的做法,靜態(tài)批處理時(shí),合并后的幾何結(jié)構(gòu)需要占用更多的內(nèi)存來存儲(chǔ)。這是因?yàn)椋绻粋€(gè)物體模型在靜態(tài)批處理前共享了相同的網(wǎng)格,那么在內(nèi)存中會(huì)產(chǎn)生一個(gè)該網(wǎng)格的復(fù)制品,因此當(dāng)很多物體模型共用一份網(wǎng)格,就使原本一個(gè)網(wǎng)格變成了多個(gè)網(wǎng)格發(fā)送給了GPU。這并不是一件好事,例如在濃密森林中,會(huì)使用了很多個(gè)相同的樹網(wǎng)格,如果對(duì)這些樹物體進(jìn)行動(dòng)態(tài)批處理,會(huì)產(chǎn)生嚴(yán)重的內(nèi)存開銷。所以這里是空間和時(shí)間上的一個(gè)取舍,需要在此找一個(gè)時(shí)間和空間的平衡點(diǎn)。
對(duì)物體使用靜態(tài)批處理的方法是在場(chǎng)景中選中該物體,同時(shí)在其Inspector面板中選中Batching Static靜態(tài)屬性。在內(nèi)部實(shí)現(xiàn)上,Unity首先把這些靜態(tài)物體變換到世界空間下,然后為它們構(gòu)建一個(gè)更大的頂點(diǎn)和索引緩存,對(duì)于使用同一材質(zhì)的物體。Unity只需要調(diào)用一個(gè)DrawCall就可以繪制全部物體。而對(duì)于使用不同材質(zhì)的物體,靜態(tài)批處理同樣可以提升渲染性能。盡管這些物體仍然需要調(diào)用多個(gè)DrawCall,但靜態(tài)批處理可以減少這些DrawCall之間的狀態(tài)切換,而這些切換往往是費(fèi)時(shí)的操作。
5 批處理效率分析
對(duì)Unity中動(dòng)態(tài)批處理和靜態(tài)批處理進(jìn)行簡(jiǎn)單的測(cè)試。在空間中創(chuàng)建3個(gè)物體Cube。
通過勾選物體的Inspector面板中的Batching Static靜態(tài)屬性,來實(shí)現(xiàn)對(duì)物體是否進(jìn)行靜態(tài)批處理。觀察Stats面板的Batches數(shù)量和Saved By batching數(shù)量的變化。
圖1 Unity中的Stats面板
在Unity中Batches數(shù)量相當(dāng)于DrawCall。Saved By Batches是指通過批處理節(jié)省的Batches數(shù)量,見表1。
根據(jù)測(cè)試結(jié)果,只有使用相同材質(zhì)的物體,再通過批處理可以從一定程度上降低DrawCall。將測(cè)試用的Cube更換成Capsule時(shí),使用同一材質(zhì)無法進(jìn)行動(dòng)態(tài)批處理,這是因?yàn)閷?duì)于頂點(diǎn)數(shù)太多的物體,無法進(jìn)行動(dòng)態(tài)批處理,所以DrawCall沒有減少。
6 結(jié)束語
(1)如果不同的物體共享材質(zhì),則可以直接通過靜態(tài)批處理降低DrawCall。
(2)如果無法進(jìn)行靜態(tài)批處理,而要使用動(dòng)態(tài)批處理的話,那么盡可能減少物體的數(shù)目并且讓這些物體包含少量的頂點(diǎn)屬性和頂點(diǎn)數(shù)目。
(3)對(duì)于頂點(diǎn)數(shù)太多的物體(頂點(diǎn)數(shù)大于900),不能使用動(dòng)態(tài)批處理,但是可以使用靜態(tài)批處理來降低DrawCall。
參考文獻(xiàn):
[1]Fletcher Dunn,Ian Parberrry,3D數(shù)學(xué)基礎(chǔ):圖形與游戲開發(fā)[M].史銀雪,陳洪,王榮靜,譯.北京:清華大學(xué)出版社,2005:225-368.
[2]馮樂樂. Unity Shader 入門精要[M].北京:人民郵電出版社,2016.
[3]Shireiner D, Shellers G, Kessenich J M, et al.OpenGL programming guide: The Offcial guide to learning OpenGL, version 4.3[M]. Addison-Wesley, 2013. 中譯本.OpenGL 編程指南(第八版).
[4]Wright R S, Heamel N, Shellers G M, et al. OpenGL SuperBible: comprehensive tutorial and reference[M]. Pearson Education, 2010. 中譯本:OenGL超級(jí)寶典(第五版).