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