看了一篇關(guān)于明日之后的光影文章 發(fā)現(xiàn)方法很雞賊很有意思。 里面的性能優(yōu)化點(diǎn)都很不錯,純干活。轉(zhuǎn)載過來學(xué)習(xí)一下
今天要給大家?guī)淼氖敲魅罩罂蛻舳思夹g(shù)分享。明日之后是一個開放大世界的游戲,在渲染方面是比較復(fù)雜的。首先它是一個大世界,擁有3D視角,有晝夜天氣以及大量植被,環(huán)境是可以被改變的。這些在程序員看來,就會面臨光照條件不固定,場景布局不固定,面數(shù)高,DP多,Overdraw之類的問題。
光與影
帶著這些問題,看一下我們是如何制作渲染方案的。
先來回顧一下傳統(tǒng)制作方案。運(yùn)用場景光照離線烘培,角色光照實(shí)時計算的方法,使場景更加真實(shí)。但這個方法并不太適合我們的游戲,因?yàn)閱渭兓诤姹旱姆椒m然高效,但難以實(shí)現(xiàn)晝夜光照的交換。所以我們當(dāng)時就有幾點(diǎn)思考:第一,日升月落-主光源應(yīng)當(dāng)分離;第二,實(shí)時GI對于手游依然遙不可及-依然需要烘焙;第三,重新梳理光照中的各個分量,找出變與不變量。
單純的烘焙效果是無法達(dá)到《明日之后》光照變化所需的效果的。所以我們將主光源分離出來,實(shí)時計算;將烘焙貼圖的RGB存儲間接光與烘焙點(diǎn)光;烘焙貼圖的Alpha存儲AO。

烘焙貼圖的RGB在白天其實(shí)是看不見的,因?yàn)槲覀冊诎滋鞎r會將烘焙的RGB分量調(diào)到0。而在黑夜,烘焙貼圖的RGB分量權(quán)值會調(diào)高。這樣就可以做到白天沒有燈光,而夜晚有燈光以及間接光的效果。關(guān)于烘培間接光,是不存儲太陽光產(chǎn)生的直接光照,陰影的,它只存儲間接光與烘焙點(diǎn)光,根據(jù)時間調(diào)節(jié)直接光與間接光的權(quán)重,主要起到豐富夜間光照的作用,由于不需要存儲陰影,尺寸可以小很多。
但AO就不同了,AO在白天和黑夜基本是一樣的。因?yàn)锳O可以讓物體更“實(shí)”,有AO甚至可以接受沒有陰影,烘焙時天光只產(chǎn)生AO,不產(chǎn)生光照,另外AO存儲在烘焙貼圖的Alpha通道。
以上基本就解決了場景烘焙基調(diào)的問題了,也就是場景靜態(tài)光照的問題。但美術(shù)發(fā)現(xiàn),在這樣一套光照下行走,人物不受光照影響,顯得光照不夠豐富,畫面相對平面化。
所以我們就運(yùn)用了模擬GI技術(shù),它是一種叫Ambient Cube的技術(shù)。它會在場景里擺很多采樣點(diǎn),每個采樣點(diǎn)記錄6個方向的光照信息,利用烘焙器離線生成(網(wǎng)易自研Cloud GI)簡單高效,大幅增強(qiáng)了夜間光照真實(shí)感與豐富度,它也可替換為SH來提升質(zhì)量。
接下來就是動態(tài)點(diǎn)光源的問題,類似于游戲里的火把。但Ambient Cube只能實(shí)現(xiàn)靜態(tài)點(diǎn)光,Deferred框架不適合移動平臺。這時我們就回到點(diǎn)光源特性的問題,點(diǎn)光源有距離衰減的特性。我們運(yùn)用了Tiled Point Light這一技術(shù),將畫面切分為多個tile,利用上一幀的深度計算tile的world position,然后計算出tile貢獻(xiàn)最大的2個點(diǎn)光,使得每個頂點(diǎn)/像素僅需計算2個點(diǎn)光。Tiled Point Light使得我們開銷降低(iphone 5s也可使用),大大豐富了場景的光照效果。

接下來就有了這樣的光照匯總

主光源實(shí)時計算
烘焙貼圖的RGB存儲間接光與烘焙點(diǎn)光
烘焙貼圖的Alpha存儲AO
Ambient Cube實(shí)現(xiàn)夜間和室內(nèi)GI
Tile-based Point Light實(shí)現(xiàn)動態(tài)點(diǎn)光源
全場景陰影實(shí)時計算

提到陰影,陰影對3D視角的游戲來說幾乎是不可避開的坑,Shadow Mapping在未來幾年內(nèi)應(yīng)該還是主流方法,3D視角的陰影比2.5D視角難做很多,場景參與投影更是個大坑。Shadow Mapping的優(yōu)點(diǎn)是它具有非常簡潔的原理,相對開銷低(但也有很多坑)它具有海量的變種算法,在未來幾年內(nèi)應(yīng)該還是主流方法,全場景陰影可能會越來越主流。如果用一句話來概括就是:如果在燈光視角看不到物體A,那么物體A就在陰影中。
但這也經(jīng)常會遇到問題,其中一個比較嚴(yán)重的問題就是大場景的問題:3D視角游戲常常平視場景,陰影透視走樣嚴(yán)重;使用單張超大Shadow MAP,遠(yuǎn)處精度嚴(yán)重浪費(fèi)。所以我們引入了Cascade Shadow Maps,使用多級Shadow Map,拆分遠(yuǎn)近物體,盡量充分利用精度,這也是LOD思想的一種應(yīng)用。PSSM是一種比較流行的做法,但《明日之后》使用的則是以相機(jī)為中心建立多級嵌套的Shadow Map。它使外層Shadow Map可以緩存,隔幀更新,減少DP,相機(jī)在小范圍內(nèi)移動時,可以完全不更新外層,DP開銷接近0,實(shí)踐上每幀均攤DP只有十來個。但它也有缺點(diǎn),遠(yuǎn)處的陰影質(zhì)量不如PSSM,難以實(shí)現(xiàn)超遠(yuǎn)距離的陰影。
接下來時植被問題:場景中有大量制備,大量Overdraw,陰影也存在被重復(fù)計算的問題。所以我們用Screen Space Shadow,使繪制場景時不計算陰影,最后一個Pass利用深度重構(gòu)像素的世界坐標(biāo),并計算陰影,減少陰影的Overdraw。這樣能減少GPU Time,從16.8ms減少到14.3ms。陰影也不是承在方向光上,而是承在最終顏色上,會讓被光面變得更黑。

關(guān)于渲染這一塊還想分享的是雨雪渲染。雨雪實(shí)際上是使用椎體包圍相機(jī),椎體行播放多層紋理動畫來實(shí)現(xiàn)的。我們將近處和遠(yuǎn)處的雨都分開三個通道存在貼圖里,做一個層次變化,在椎體上播放。

關(guān)于濕身效果非常有趣,它是通過調(diào)節(jié)PBR的金屬度/粗糙度來模擬濕身效果,在PBR框架下無額外開銷,所以不用白不用。
優(yōu)化
關(guān)于方案就講到這,接下來講講優(yōu)化方面是怎么做的。首先是渲染效率的問題,3D大場景的DP數(shù)非??植?,移動設(shè)備CPU/GPU都很弱,對DP數(shù)量非常敏感。我們的思路是:剔除不必要的DP,合并零碎的DP,優(yōu)化單DP效率。

首先我們做了遮擋剔除,在視錐剔除的基礎(chǔ)上,進(jìn)一步剔除被遮擋的物體。最適合手游的遮擋剔除方案是PVS(Potentially visible set),它將相機(jī)可達(dá)空間切分為多個Cell,光線追蹤計算每個Cell可看見哪些模型,使用bitset等數(shù)據(jù)結(jié)構(gòu)保存可見性信息。運(yùn)行時,我們就根據(jù)相機(jī)位置找到對應(yīng)的Cell可見性信息,用于剔除不可見模型。
接下來進(jìn)行合批。相同材質(zhì)的物體會被合批,以一個DP繪制出來,合批發(fā)生在加載線程,生成額外頂點(diǎn)數(shù)據(jù)。有相同材質(zhì)的要求,就意味著物體之間需要共享貼圖,才能用一個指令繪制出來。這樣會遇到很多問題:美術(shù)需要把多個模型的貼圖合并到一張(隨緣合);每個模型的UV都需要重新調(diào)節(jié)一下(很麻煩);后續(xù)增加模型.修改模型.刪除模型,都需要調(diào)整UV;維護(hù)成本高;只要修改一個模型貼圖,就會產(chǎn)生大貼圖的Patch體積;跨場景共享模型會造成內(nèi)存浪費(fèi)。針對這些問題,我們制定了改進(jìn)方案:離線僅預(yù)計算合批策略;貼圖合并改為加載時進(jìn)行。針對場景結(jié)構(gòu)設(shè)計一種貪心算法,自動搜索哪些模型應(yīng)當(dāng)被合批,計算合批信息,僅需保存貼圖的合并信息,合并操作留到運(yùn)行時再做。運(yùn)行時創(chuàng)建被合批貼圖時,在內(nèi)存里將多張壓縮貼圖合并一張Atlas,ASTC/ETC2/PVR都是Block-based的壓縮算法,按Block拷貝即可合并,合并的時間開銷很小,和I/O相比可以忽略不計。引擎加載模型時,查詢貼圖是否被合批,如果被合批,則根據(jù)貼圖的合批信息調(diào)整自己的UV即可。最終的合批效果比人肉做可能還會好一些,美術(shù)也不需要花費(fèi)大量時間去做合批,修改貼圖不再會導(dǎo)致巨大的Patch。
除此之外,游戲中需要大量植被,植被雖做了LOD,但面數(shù)依舊很高。我們的思路是將它們渲染到Render Target,再以Billboard面片方式批量繪制。為什么不離線做呢?第一個原因是因?yàn)椴幌朐黾影w,其次一些動態(tài)的信息可能需要渲染到RT里。最后的成果是新手場景面數(shù)從20萬減少到17萬,新手場景GPU Time從14.3ms減少到12.3ms,并且因?yàn)樯Ь嚯x遠(yuǎn),所以不太容易看出瑕疵。

最后講一塊,預(yù)算機(jī)制。啟發(fā)點(diǎn)首先是因?yàn)橛嬎隳芰κ怯邢薜?,我們需要對任?wù)建立重要度分級。所以我們需要建立資源消耗和計算能力的閉環(huán),從以前的”來幾個,處理幾個”,轉(zhuǎn)變?yōu)椤蹦芴幚韼讉€,處理幾個”的負(fù)反饋機(jī)制。然后當(dāng)消耗達(dá)到預(yù)算上限時,延遲/放棄低優(yōu)先級任務(wù),或者換出低優(yōu)先級資源。
這里我舉兩個例子。第一:CPU預(yù)算,CPU資源是有限的,為了達(dá)到30fps,每幀預(yù)算只有33ms,那么我們可以使用預(yù)算管理異步回調(diào)。第二:內(nèi)存預(yù)算,NeoX中的紋理預(yù)算系統(tǒng)。我們可以通過嚴(yán)格控制紋理的內(nèi)存的使用量,根據(jù)紋理對于場景的貢獻(xiàn)度打分.排序,將分值低的紋理切換到低分辨率的Mipmap來實(shí)現(xiàn)對紋理內(nèi)存的嚴(yán)格管控。

總結(jié)
光影表現(xiàn)對新游戲而言非常重要,實(shí)時化是個大趨勢,手游的技術(shù)路線并不完全與端游的老路一致,沒有銀彈,希望大家勇于探索新技術(shù)。
原鏈接:http://game.academy.163.com/open-day/201901/