基于RadeonRays的光线追踪全局光照实现方案
基于 RadeonRays 的光線追蹤全局光照實(shí)現(xiàn)方案
最近半年一直在做全局光照方面的工作,陸續(xù)實(shí)現(xiàn)了輻射度算法和光線追蹤兩套方案,最終由于輻射度算法的局限性(只能基于漫反射)還是使用了光線追蹤的方案,是時(shí)候?qū)憘€(gè)小小的總結(jié)了。
先列一下提綱吧,希望從以下幾個(gè)方面講一講這些工作:
?
- 為什么選擇光線追蹤
- RadeonRays 簡(jiǎn)介
- 實(shí)時(shí)光線追蹤與離線光線追蹤的區(qū)別
- 光線追蹤全局光照方案的渲染管線
- 光線追蹤方案實(shí)現(xiàn)過(guò)程中的經(jīng)驗(yàn)和教訓(xùn)
- 一些效果展示
為什么選擇光線追蹤
相信很多游戲開(kāi)發(fā)者,特別是做游戲引擎的猿,會(huì)對(duì)渲染效果很癡迷,而全局光照是渲染效果呈現(xiàn)的一個(gè)很重要的因素,在2017GDC 中 Unity 和 AMD 發(fā)布了基于 RadeonRays 的 Progressive Lightmap 的全局光照實(shí)現(xiàn)方案,和 Unity 之前的 Enlighten 的方案研究對(duì)比了一下,無(wú)論在效率還是效果方面都有了很大的提升,再加上自己對(duì)于新技術(shù)的熱愛(ài)(其實(shí)是 Leader 的逼迫),有了把 RadeonRays 方案移植到我們引擎的想法。其實(shí)在這之前實(shí)現(xiàn)了輻射度算法的方案,但是效率和效果實(shí)在是難以忍受,所以開(kāi)始光線追蹤的預(yù)研,半個(gè)多月之后居然移植過(guò)來(lái)簡(jiǎn)單的跑通了,極大的增強(qiáng)了自信心,于是繼續(xù)攻克難關(guān)實(shí)現(xiàn)了它。后來(lái)看到報(bào)道2018GDC 中 UE4和 NVIDIA 聯(lián)合發(fā)布了實(shí)時(shí)光線追蹤的解決方案,DX 也適配了光線追蹤的渲染管線,感覺(jué)光線追蹤應(yīng)該是現(xiàn)在的趨勢(shì)。
RaydeonRays 簡(jiǎn)介
RaydeonRays 是 AMD 的一套光線追蹤的解決方案,它支持三個(gè)后端:OpenCL, Vulkan,以及 Embree, OpenCL 使用支持至少 OpenCL 1.2的 GPU 和 CPU,Vulkan 支持 Vulkan 1.0以上的 GPU, Embree 支持 Intel 優(yōu)化的 CPU 光線追蹤設(shè)備軟件。當(dāng)然,在如今 GPU 性能越來(lái)越好的時(shí)代,能用 GPU 就別用 CPU 了,我選用了 GPU 的 OpenCL 方案,當(dāng)然,選它也是因?yàn)?RaydeonRays 在 Github 開(kāi)源了,雖然無(wú)法照搬,但是很多東西還是可以借鑒學(xué)習(xí)的。
據(jù) Unity 所說(shuō),使用 RadeonRays 的 Lightmap 烘培方案比之前快了10-20倍,之前需要一天才能渲完的場(chǎng)景現(xiàn)在一個(gè)小時(shí)就能渲染完了,具體是真是假我也沒(méi)實(shí)驗(yàn)過(guò)。
實(shí)時(shí)光線追蹤與離線光線追蹤的區(qū)別
所謂的實(shí)時(shí)光線追蹤,就是隨著攝像機(jī)視角的變動(dòng),后端需要實(shí)時(shí)發(fā)射追蹤光線來(lái)重新計(jì)算光照信息,如果屏幕分別率很高,這個(gè)計(jì)算量是很大的,對(duì) GPU 的性能要求是很高的,如果性能達(dá)不到游戲直接會(huì)卡死。而離線光線追蹤則不會(huì)造成這種情況,即使設(shè)置了很高的光線追蹤采樣率,很多的反射次數(shù),無(wú)非是烘焙 Lightmap 的時(shí)間會(huì)變長(zhǎng),最終還是可以渲染出效果很好的的 Lightmap 供場(chǎng)景使用。所以現(xiàn)階段還是全局光照中的光線追蹤方案占主流,NVIDIA 雖然發(fā)布了新的 TURING 架構(gòu)顯卡引入光線追蹤框架,但是實(shí)時(shí)光線追蹤真正進(jìn)入游戲普及估計(jì)還是任重道遠(yuǎn)(希望能很快打臉)。
光線追蹤全局光照方案的渲染管線
關(guān)于光線追蹤的基本原理,其實(shí)還是比較簡(jiǎn)單的,簡(jiǎn)單來(lái)說(shuō)就是向場(chǎng)景發(fā)射 N 條光線,然后根據(jù)碰撞點(diǎn)的材質(zhì)進(jìn)行 BXDF,BRDF 的運(yùn)算,然后(根據(jù)俄羅斯輪盤)再進(jìn)行漫反射,鏡面反射,或者折射,如此循環(huán)直到光線逃離場(chǎng)景或者到達(dá)最大反射次數(shù),最后對(duì) N 條光線進(jìn)行蒙特卡洛積分即可獲得結(jié)果。對(duì)于實(shí)時(shí)光線追蹤和離線光線追蹤,這里發(fā)射光線的方式還是有些差異的:實(shí)時(shí)光線追蹤是從視點(diǎn)發(fā)射光線,光線數(shù)量一般是屏幕的大小,比如屏幕是1920*1080, 則需要發(fā)射1920*1080條射線,每條射線對(duì)應(yīng)一個(gè)像素點(diǎn),依照需求,可能要發(fā)射多次來(lái)采樣平均得到理想的結(jié)果;而對(duì)于離線光線追蹤,每個(gè)靜態(tài)物體都要根據(jù)光照 UV 生成 M 個(gè) Patch(數(shù)量和 Lightmap 大小有關(guān)),每個(gè) Patch 要向法線方向的半球發(fā)射 N 條射線(數(shù)量由用戶采樣數(shù)量決定),最終對(duì) N 條射線進(jìn)行蒙特卡洛積分,得到這個(gè)物體的 Lightmap。
具體的實(shí)現(xiàn)過(guò)程可以參照 Unity 的實(shí)現(xiàn)方案,貼一個(gè)他們方案的偽代碼:
?
本來(lái)想自己畫一個(gè) PipeLine 的流程圖的,但是忽然想起之前看的 UE4的視頻中看到過(guò)類似的,就回頭找了一下直接把他們的貼上來(lái):
?
需要補(bǔ)充的是,對(duì)于 Miss 的光線,我做的處理是給它賦予環(huán)境球(當(dāng)作天光)的顏色,而每次處理完最近的碰撞之后,需要發(fā)射陰影檢測(cè)射線以及重新計(jì)算的反射光線,二手QQ買號(hào)底層的加速結(jié)構(gòu)我用的 bvh,可以加包圍盒也可以直接把三角形掛在上面。
光線追蹤方案實(shí)現(xiàn)過(guò)程中的經(jīng)驗(yàn)和教訓(xùn)
因?yàn)槭菑囊桓F二白的狀態(tài)開(kāi)始的,所以過(guò)程中遇到的坑實(shí)在是太多太多,很多可能都沒(méi)記錄流失了,這里就搬一下印象比較深刻,記錄在案的吧。
剛開(kāi)始生成 Lightmap 是逐像素的,現(xiàn)在想想當(dāng)時(shí)的思路是太蠢了,沒(méi)有合理運(yùn)用好 GPU 的特性,后來(lái)用逐 Lightmap 的方式,效率提升了成百上千倍。
材質(zhì)層開(kāi)始沒(méi)搞的很明白,結(jié)果就是 Lightmap 渲染出來(lái)效果總是不理想,比如石頭邊緣會(huì)漏光等等,后來(lái)仔細(xì)看了看底層的材質(zhì)算法,才算弄好了。后來(lái)又惡補(bǔ)了一下 BRDF 的一些算法和邏輯,感覺(jué)這方面做好還是挺不容易的,最近 Google 開(kāi)源了 filament 的項(xiàng)目代碼,還有一些文檔,特別是對(duì)于移動(dòng)端的優(yōu)化寫的還是挺好的,在這里推薦一下。
隨機(jī)光線的生成,開(kāi)始是用的 c++ rand 方法直接在半球生成光線,后來(lái)用了 cosineSampleHemisphere 算法,最好再加個(gè)分層采樣,比之前的效果噪點(diǎn)少一些。
一些并行的運(yùn)算,只要能在 GPU 里面計(jì)算,盡量放到 GPU,放到 kernel 里面計(jì)算比 CPU 快的多得多,CPU 和 GPU 交互讀取數(shù)據(jù)會(huì)比較耗費(fèi)性能,這方面的操作能少做就盡量少做。
還有就是材質(zhì)內(nèi)存方面,盡量所有物體設(shè)置成同一屬性 Instance,不然內(nèi)存老是崩潰,這是底層的問(wèn)題,另外在引擎客戶端方面做了一些場(chǎng)景物體和燈光的剔除,也有改善作用。
對(duì)于 AlphaTest,開(kāi)始想了好多辦法,不想把 alpha 貼圖傳進(jìn)射線檢測(cè)層,但是后來(lái)效果都不好,還是乖乖傳了 alpha 貼圖。
一些漏光問(wèn)題,很多時(shí)候是因?yàn)槟P?UV 劃分問(wèn)題,或者 Lightmap 大小不夠,像素太少導(dǎo)致的。
還有噪點(diǎn)問(wèn)題,一開(kāi)始采樣燈光是用的隨機(jī)采樣,這樣燈光多了很容易出現(xiàn)噪點(diǎn),最后直接遍歷所有燈光,這樣雖然效率方面降低了不少,但是最后噪點(diǎn)基本很少,用效率換效果,最后其實(shí)效率也還可以接受,這樣所有路徑最終只需要遍歷一次就夠了。
當(dāng)然還有很多服務(wù)器和各種自己粗心失誤的問(wèn)題,印象比較深的一次是 Github 代碼改了之后找不到原版了,下的還不是 Release 版本,幸虧 Git 比 SVN 好一些,能恢復(fù)到某一時(shí)間點(diǎn)之前的代碼,萬(wàn)幸啊……
一些效果展示
首先貼一個(gè)木屋的測(cè)試效果:
在左側(cè)面還是可以看到光線追蹤的反射效果的。
然后嘗試渲染了一個(gè)項(xiàng)目比較大的場(chǎng)景:
?
光線追蹤渲染出來(lái)的效果整體會(huì)更豐富生動(dòng)一些,當(dāng)然這個(gè)版本還是當(dāng)時(shí)不成熟的版本,仔細(xì)看還是有些問(wèn)題的。
最后貼一個(gè)受到 UE4啟發(fā)做的一個(gè)面光效果:
?
面光的虛化陰影效果還是挺好的。
歡迎大家分享交流。
總結(jié)
以上是生活随笔為你收集整理的基于RadeonRays的光线追踪全局光照实现方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《穿越火线:枪战王者》手游客户端技术方案
- 下一篇: Unity动画系统经验谈:换装系统与骨骼