gdc19年,一直開發地鐵系列的4A games;
4A games是成立于2006年,烏克蘭開發商,一直做metro系列遊戲,三個大版本,中間兩個重制版。
技術上一直metro是比較激進的,是硬體廠商show技術的常客,這次raytracing也沒有缺席.
一些細節的效果對比可以看這裡:
https://www.bilibili.com/video/BV1M5411s7v4/
本文聊得是gdc19上4AGames的talk,也是個人認為到目前為止(2020.5.6)講遊戲中使用raytracing中最好的一篇。
我們可以看到從整體上看,rt版本的光照更加的完整自然。
用RayTracing做了什麼
4AGames是用stochastic的方式,用raytracing做了RTAO,RTGI
這裡也代表了raytracing技術帶來的幾個明顯提升點:
- RTAO對比ssao,實體正确的多
-
RTGI對比voxel based gi:在同等效率下,精度&trace範圍上有很大的優勢
這裡也要補充下,如果實際玩遊戲的話,會發現提升其實一般,這個在digital foundry裡面會有盡可能的充分比較,但是在玩家視角來看,可能還是提升有限。
這裡很重要一點是受限于地鐵遊戲的畫風非常的“頹廢感”,導緻光照優勢沒法充分展現,但是拆開到ao到gi,可能看到單項上的提升是有限的。
可以說在metro中,光追技術開始充分展現了它的潛力,metro也做了遠不止是把光追feature用用的程度,有了很不錯的探索。
btw:
stochastic的方式,就是以一些随機分布的方式在空間上低頻采樣,然後再通過denoise來複原畫面的方式:
(如圖,左邊是stochastic根據一些機率分布函數在空間中采樣計算,然後結合空間&時間(temperal)資訊做denoise,就是右邊的結果了)
pipeline
這裡是整體的pipeline。
這個部分介紹整體pipeline的情況,其中兩個要點:irradiance表達和denoise後面單獨章節來說。
acceleration structure管理
在nvidia目前的turing架構下,是要建立bvh((bounding volume hierarchy))作為acceleration structure。
compute shader有的特性,在bvh建構的時候都有,比如async compute。
這裡有top level acceleration structure和bottom level acceleration structure。
各自更新原理比較簡單,地鐵裡也介紹了些技巧,不贅述。
raytracing階段
1,pre trace,
這裡先通過一些更便宜的計算,盡量規避掉比較費的raytracing,比如raymarch地形的depth等等
這部分raymarch會和bvh建構一起通過async compute同時做,
- bvh建構是一個compute shader的工作
-
async compute會讓raymarch的部分幾乎免費
2,ray trace
pre trace中沒有intersection的地方,在螢幕空間,每個像素,按照brdf的分布來做raytrace,結果保留distance+albedo;
3,ao
有了distance,RTAO就很自然了,做AO+filtering
4,gi
以trace的結果做lighting計算,能用上的優化都用上,比如重用deferred lighting已經計算好的部分,用atmosphere中計算好的部分;
已經計算好的部分(也就是frustum之外的)就再做次計算。
這裡真正麻煩的部分是denoise,可以看到做了兩遍denoise。
irradiance storage
在lighting階段,會計算raytrace到的hit點的光照,這個光照如前所述,可以預計算,可以重用deferred lighting,可以重新計算。
結果是一個hdr的rgb的值,metro在encoding的時候是轉到ycocg空間,然後y分量用L1的spherical harmonics來表達,cocg還是标量。
分離cocg這裡還是人眼對顔色不敏感,而對于亮度敏感所緻。
然後後續的所有denoise和accumulate都是在這個空間裡做的。
一共耗費96bit。
其他情況,壓到ldr空間等等,在一些極限情況,會損失效果,對于大範圍denoise結果不好。
這裡metro隻是泛泛而談,實際做的話,可以實際嘗試下,拿到切實的原因。
然後trace的結果用sh存的,也是一個低精度的cubemap,是以用來做非常glossy的reflection也是可以的。
denoise
raytracing通過硬體能做到相當的實時,但是還遠不到可以計算足夠的ray的情況。
是以我們隻能用少量的ray來模拟近似,也就是用stochastic(随機)的方式,然後通過denoise來恢複畫面。
這裡denoise總體上兩個方向:convolution based(卷積)和deep learning based。
目前相對成熟的是convolution based,比較期待deep learning方向的發展。
metro也提到denoise是最繁瑣的階段,nvidia在gdc2020上的talk也建議大家把denoise盡量早的開始(确實很難也很煩)。
denoise部分主要考慮兩個因素:
- spatial:什麼空間,什麼數量,kernal如何分布
- temperal
spatial
1,screen space or world space
使用world space更加正确;
2,uniform or not
metro用的quadratic kernel來做。
3,權重使用normal base還是plane base
權重是基于geometry表面的tangent plane來,可以讓結果更加穩定,而不是基于normalmap的結果。
4,半徑和sample數量的adaptive選擇
這裡就是盡量減少sample的數量,實際情況會根據,距離,方差和ao來選擇;
距離不解釋了。
ao就是這裡會比較暗,是以少sample一些ok。
(可以看到方差不同的地方,sample數量有所不同)
variance就是變化比較小的地方,就blur的少一些,sample點也少一些。
當幀的sample點方差都是比較大的,随着temperal的積累,方差會逐漸降低。
temperal
temperal這裡就是用了積累多幀的情況,類似taa方面。
這裡metro主要做了兩件事情:
- temperal accumulation先于denoise
-
temperalAccumulation+Denoies的pass做兩遍
這兩件事情在是整篇talk的highlight,是有很見解的部分,看的爽!
temporal->denoise
這裡列了下temporal->denoise和denoise->temporal兩種方式下各自優劣勢。
實際做的時候,ghosting一直也是非常讓人頭疼的地方。
這裡是我們自己在做開發時候遇到的,就是denoise的時候會做blur,把周圍的像素blur過來,這時候遇到動态物體的部分,就會出現ghost,然後通過temporal accumulation蔓延出去,變成ghost。
multi denoise pass
metro這個部分包括兩點:
- 分兩個pass來做,第一個pass是blur範圍比較大,6m;第二個pass是blur範圍比較小3m,并且加上normal資訊
- 每個temporal pass是用自己這個pass之前的結果(feedback),不是用下一個pass的上一幀的結果
運作效率
總體還是可以的。