gdc19年,一直开发地铁系列的4A games;
4A games是成立于2006年,乌克兰开发商,一直做metro系列游戏,三个大版本,中间两个重制版。
技术上一直metro是比较激进的,是硬件厂商show技术的常客,这次raytracing也没有缺席.
一些细节的效果对比可以看这里:
DigitalFoundry聊地铁逃离的光线追踪技术效果_哔哩哔哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com![7de8caefc51c9178cefe061a1052fbb9.png](https://i-blog.csdnimg.cn/blog_migrate/bff17a9fccc6b11022ba930cee4393ad.jpeg)
本文聊得是gdc19上4AGames的talk,也是个人认为到目前为止(2020.5.6)讲游戏中使用raytracing中最好的一篇。
![ccfe14d0ddaaf887b07ea8e154e50f59.png](https://i-blog.csdnimg.cn/blog_migrate/ee62907f8d69cfe4bbf15fa11cf3d84f.jpeg)
我们可以看到从整体上看,rt版本的光照更加的完整自然。
用RayTracing做了什么
4AGames是用stochastic的方式,用raytracing做了RTAO,RTGI
![8939f895019e6d4bf3d8e5fb2411cc2c.png](https://i-blog.csdnimg.cn/blog_migrate/de2fe1e88aeaaab69e9e0dbb2729f799.jpeg)
这里也代表了raytracing技术带来的几个明显提升点:
- RTAO对比ssao,物理正确的多
- RTGI对比voxel based gi:在同等效率下,精度&trace范围上有很大的优势
这里也要补充下,如果实际玩游戏的话,会发现提升其实一般,这个在digital foundry里面会有尽可能的充分比较,但是在玩家视角来看,可能还是提升有限。
这里很重要一点是受限于地铁游戏的画风非常的“颓废感”,导致光照优势没法充分体现,但是拆开到ao到gi,可能看到单项上的提升是有限的。
可以说在metro中,光追技术开始充分展现了它的潜力,metro也做了远不止是把光追feature用用的程度,有了很不错的探索。
btw:
stochastic的方式,就是以一些随机分布的方式在空间上低频采样,然后再通过denoise来复原画面的方式:
![c1a16d5d29ab54f0521e25dd5a0dc754.png](https://i-blog.csdnimg.cn/blog_migrate/497936a21aa4e5fe58dbe9f89cec241f.jpeg)
(如图,左边是stochastic根据一些概率分布函数在空间中采样计算,然后结合空间&时间(temperal)信息做denoise,就是右边的结果了)
pipeline
![cbf61b7ea21a37edf2a25b023214b30f.png](https://i-blog.csdnimg.cn/blog_migrate/69e211a2bd956d21732a50c6b2b509b3.jpeg)
这里是整体的pipeline。
这个部分介绍整体pipeline的情况,其中两个要点:irradiance表达和denoise后面单独章节来说。
acceleration structure管理
在nvidia目前的turing架构下,是要建立bvh((bounding volume hierarchy))作为acceleration structure。
compute shader有的特性,在bvh构建的时候都有,比如async compute。
![71c6616ac853ff3f3b05dbc9bf423003.png](https://i-blog.csdnimg.cn/blog_migrate/4d1c231771bc27be675aee7d8fcaa732.png)
这里有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
![67054198a22de821f01ee788f10d9eec.png](https://i-blog.csdnimg.cn/blog_migrate/42585b29d825dde9421219bf91a0a2c6.jpeg)
pre trace中没有intersection的地方,在屏幕空间,每个像素,按照brdf的分布来做raytrace,结果保留distance+albedo;
3,ao
![54d3cbb6c697d136cada103e5c7bd24f.png](https://i-blog.csdnimg.cn/blog_migrate/533d22e9a484a6e8e521da6ce3c76d93.jpeg)
有了distance,RTAO就很自然了,做AO+filtering
4,gi
![e030759a8900127463dfd4f8eb62aac0.png](https://i-blog.csdnimg.cn/blog_migrate/6bc2852012bc60a70ed108666c3e19a2.jpeg)
以trace的结果做lighting计算,能用上的优化都用上,比如重用deferred lighting已经计算好的部分,用atmosphere中计算好的部分;
已经计算好的部分(也就是frustum之外的)就再做次计算。
这里真正麻烦的部分是denoise,可以看到做了两遍denoise。
irradiance storage
![7765a247563e98f95ae8d189fcf8fb42.png](https://i-blog.csdnimg.cn/blog_migrate/311307c432fdb0a434d1ef594aa6a254.png)
在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也是可以的。
![c0dc8883123f529b5a08f8bffcee2662.png](https://i-blog.csdnimg.cn/blog_migrate/13d03722f1fb95aef6bfd77ae29e5a80.jpeg)
![92c1b8cc398b422203e6b41919e9d80d.png](https://i-blog.csdnimg.cn/blog_migrate/2d2dd7ac81978240029f2d1cb9447cfa.jpeg)
denoise
![c1a16d5d29ab54f0521e25dd5a0dc754.png](https://i-blog.csdnimg.cn/blog_migrate/497936a21aa4e5fe58dbe9f89cec241f.jpeg)
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
![9b2c567f7939ce4f8c9cf12cf2ef6baa.png](https://i-blog.csdnimg.cn/blog_migrate/dcb0852dfba6a0a3b8e244c59162c8c9.jpeg)
使用world space更加正确;
2,uniform or not
![709b5d622587e092bbfb9870b41078ec.png](https://i-blog.csdnimg.cn/blog_migrate/a57d667088aa134a33e83cacd91ba1b0.jpeg)
metro用的quadratic kernel来做。
3,权重使用normal base还是plane base
![3d1bd4bdaa4c339f9f3eab899e99b7a0.png](https://i-blog.csdnimg.cn/blog_migrate/51b526b9c8d25001d57bcdc87352311d.png)
权重是基于geometry表面的tangent plane来,可以让结果更加稳定,而不是基于normalmap的结果。
4,半径和sample数量的adaptive选择
这里就是尽量减少sample的数量,实际情况会根据,距离,方差和ao来选择;
![581728262bdeb71b5c21c62f9fd14bfc.png](https://i-blog.csdnimg.cn/blog_migrate/552778230dd35e4c0a5c8f8a0f2abee4.png)
距离不解释了。
ao就是这里会比较暗,所以少sample一些ok。
![29737150a3bbc424a883f262740dcbbc.png](https://i-blog.csdnimg.cn/blog_migrate/b3c85d5e6cff19df57f9cfc80e81e09a.jpeg)
(可以看到方差不同的地方,sample数量有所不同)
variance就是变化比较小的地方,就blur的少一些,sample点也少一些。
当帧的sample点方差都是比较大的,随着temperal的积累,方差会逐渐降低。
temperal
temperal这里就是用了积累多帧的情况,类似taa方面。
这里metro主要做了两件事情:
- temperal accumulation先于denoise
- temperalAccumulation+Denoies的pass做两遍
这两件事情在是整篇talk的highlight,是有很见解的部分,看的爽!
temporal->denoise
![e64017d0df0ec690db9633fc905a9fd2.png](https://i-blog.csdnimg.cn/blog_migrate/8ca6c7fd2b8705b8dd15e26fdbafa34f.png)
这里列了下temporal->denoise和denoise->temporal两种方式下各自优劣势。
实际做的时候,ghosting一直也是非常让人头疼的地方。
这里是我们自己在做开发时候遇到的,就是denoise的时候会做blur,把周围的像素blur过来,这时候遇到动态物体的部分,就会出现ghost,然后通过temporal accumulation蔓延出去,变成ghost。
multi denoise pass
![3a907552d64a4bc09e9c81099340c936.png](https://i-blog.csdnimg.cn/blog_migrate/ae3728e41999de4ecc5ccd51fd87a8fe.png)
metro这个部分包括两点:
- 分两个pass来做,第一个pass是blur范围比较大,6m;第二个pass是blur范围比较小3m,并且加上normal信息
- 每个temporal pass是用自己这个pass之前的结果(feedback),不是用下一个pass的上一帧的结果
运行效率
![a81c0fc9b53bab9b935d8d788988419b.png](https://i-blog.csdnimg.cn/blog_migrate/c61c9d16b04101a8818d79fa1698c35e.jpeg)
Reference
EXPLORING RAYTRACED FUTUREIN.METRO EXODUS