Origin
zhuanlan.zhihu.com
Tags
开放世界
性能优化
渲染
经验分享
项目
荒野大嫖客2
收藏夹
创建时间
收藏类型
Cubox 深度链接
更新时间
原链接
描述
《荒野大镖客 救赎 2》作为去年的最佳叙事和最佳演出获得者,在环境氛围和人物动画的渲染上表现出了无可比拟的效果。而它的天气系统也为游戏中的故事叙事增色不少,让玩家在享受游戏的过程中也能够深切感受到第二次工业革命时代美国西部的氛围。
notion image
今年 SIGGRAPH R 星也过来分享了他们在大镖客天气系统开发过程中的一些技术细节,看后感觉干货很多,记下笔记作为自己学习参考。由于我自身经验不足,加上分享中的一些技术细节都和他们自己项目比较相关,因此有些翻译和理解可能会不准确,欢迎在评论区提出来。
notion image
首先上来先讲了游戏的整体风格目标与参考,大镖客 2 是初代故事的前传,发生在 18 世纪中期,那时候的美国西部城镇仍然很少,因此自然景色成了游戏的主体,团队也为此找了很多当时的风景画作为参考。
notion image
notion image
首先大致解释了什么是基于物理的 Volumetric 散射模型,当光照射到 volume 的粒子时,会有一部分被吸收或反射。朝相机位置散射的光子在光路上属于 in-scattering,而那些其他方向的则属于 out-scattering,同样也会影响到其他物体表面或者粒子的光照。这两部分的算法都和下图算式中的 P(Phase function)相关。
这就是常说的 multi scattering,通常为了简化模型只会去考虑参与透射这部分(transmittance)的 out-scattering 部分。
对于每个粒子可以把它的散射光计算分为 Visibility 和 Phase function,具体 Phase function 是什么后文会提到,这里先知道就是个概率密度函数就好。
透射部分的计算用了 Beer’s law 的指数衰减函数,描述了光线穿过 volume medium 的强度,受 volume 本身的 extinction 系数影响。
notion image
这里贴张 15 年 EA 他们在 Siggraph 的分享,可以看出就是同一套光照模型。
notion image
设计理念尽量接近现实中的物理效果,实现出一套支持各种天气效果的系统。
notion image
整个系统的结构,分为三大块展开来讲。
notion image

Data model

notion image
Cloud Map 的 RG 通道分别存了两个云层,通过 mask 和噪声图生成,同时受到游戏中天气和时间参数的影响
notion image
notion image
Cloud Height Map,RGBA8 存 altitude-based shape 信息来云雾高度上的变换,大镖客支持层云(stratus)和积云(Cumulus),同时采样也受到天气参数的影响。
notion image
Cloud Detail 参考了地平线在 15 年分享的做法,分别在 xy 和 xz 方向采样两次 2D 的 displacement vector map,然后根据环境中的风力去得到 3D noise LUT 中的图。
notion image
贴出了代码,可以很清楚的看到他们云的做法,这里可以看到还用了 Cloud Height Lut 的 z 通道来控制噪声变化的强度。
notion image
根据 Cloud Map 还可以实现这种雨汽的效果
notion image
Localized Fog 通过 Fog Map 实现,和 Cloud Map 一样覆盖了游戏中的所有可游玩区域。
Fog Map 三个通道分别存了 fog 起始高度、衰减距离和密度,生成的时候同样也受天气和时间的影响。
notion image
全局的高度雾和 localized fog 结合后的效果,画面上体积感很好。
notion image
另外一种 localized fog 的实现是让美术在场景里去摆 Fog Volumes,基本原理就是 particles 配合 alpha blending 或者 additive。
notion image
notion image

Rendering

notion image
和 guerrilla 他们一样用的 nut shell 结构,近处用 froxel,远处用 ray marching。具体模型可以看他们家在 Eurographics 2018 做的分享。
notion image
Shading Model:对之前的公式做了解释,P 代表 phase function,L 代表 luminance,V 代表 visibility。注意这里说了用两束 light octave 来估计 multi-scattering,下文的公式有详细说明。
notion image
Phase Function:描述了给定波长的光在莫个角度下因为粒子发生散射的现象,即光子的概率密度函数。
大镖客 2 里面用了 Henyey-Greenstein phase function(即下图的 HG),g 是 anisotropy 值,存在 material volume 中。但是传统的 HG 只在霾这种强 scattering 的 volume 上效果比较好,并不能很好的表现 multi-scattering 和 back-scattering,于是需要做改进。
可以看到这里计算 phase function 时用了多个 HG function 来累加,去计算 multi-scattering 的效果,并用 weights 让美术去改变效果,最终为了性能只用了两个 octave 来累加。
notion image
然而效果仍然缺了 back-scattering 的部分,于是这里对最终结果做了一个 fake 效果。
notion image
最终效果非常棒,也能随着天气和时间产生丰富的变化。
notion image
notion image
Visibility:这里主要通过 shadow map 来得到物体的可见性,对于云,会额外朝主光源(太阳或者月亮)去采样 extinction 来得到更高频率的 shadow,采样的距离也受到天气和时间参数的影响。
notion image
Terrain Shadow Map 通过对 terrain 的高度图做 raymarch 获得,得到的图为 RG16F,分别存光线求交时检测得到的地形高度和 Ray Length。之后将 R 通道的 Intersection height 和 terrian shadow map 做比较得到最终的可见性结果。Ray length 可以用于比较中调整 threshold 来改进软阴影效果。
notion image
Cloud Shadow Map 以 ESM 的方式来存直接光照阴影(不知道什么是 ESM 的可以去下面链接看 Nvidia 的这篇文章),它的深度通过从光源处往云作 raymarch 获得,得到的结果会做 blur 存在 mip map 中来避免锯齿。
notion image
对于 Ambient Light,这里的 Visibility 重用了上面 cloud raymarch 的结果。远处 raymarch 渲染的会去采样一个低分辨率的抛物面贴图,并做了 Parallel reduction。对于近处 frustum 的物体直接使用烘焙好的 Irradiance probe filed,里面存了计算所需要的光照信息。
notion image
notion image
Local Lights 的做法比较节省性能,直接通过采样 light cluster volume 来得到,visibility 也是用 shadow map 去做。为了性能考虑,只了一个 HG 函数来计算做 single-scattering 模型。
notion image
Rainbows 的具体做法没怎么提,可以直接通过调整 volume 中的雨水密度来产生(下文的 material volume 会说)。
notion image
Lightning(闪电,刚看到时理解成光照了 QAQ)的做法比较简单粗暴,每个闪电会生成一个点光源到一个 list,然后去迭代计算每个点光源。
notion image
场景中的 scattered light source 大概就是这些。
notion image
上面讲的都是如何在物体表面的一个采样点去计算散射光,接下来会介绍如何去做场景中渲染物件的管理。
上面有提到,近处物体都会去采用 froxel 的方式去管理,一般情况下视锥空间形成的体素大小为 160x88x64,但在一些室内场景会适当缩小。最终生成了三个 clip-space volume。
notion image
notion image
Shadow Volume 采用 R16F 格式,存储了所有直接光照的阴影信息,包括 CSM、Cloud shadow map 和 Terrain shadow map。这里还用了 temporal filtering 来解决高频阴影细节的 undersampling。
notion image
Material Volume 比较大,又分成了两个 Sub Volume:
第一个 volume 存了 scattering 和 absorption 的系数,第二个 volume 的 R 存了 phase function 中用到的 anisotropy 值,G 存了全局的 emission 值(这里有提到渲染管线中不支持 emissive fog per volume),B 通道存了 ambient intensity,主要用于室内的 ao 效果,最后的 A 通道就是之前说的雨水密度,用来调整彩虹效果的强弱。
notion image
在 Material accumulation 这个 pass,所有的材质都会被采样然后做混合。顺序是先做 alpha additive 再做 alpha blend,这样更方便去做一些城镇建筑物的细节。而为了在室内支持不同的粒子效果(如炉火、吸烟、爆炸等),把 particles 放到最后去计算。
这里还提到所有的材质 source 都使用噪声来做 tilling,并受风力影响。
notion image
和 shadow volume 一样,这里同样对第一个 sub volume 使用了 temporal filtering。
这里还提到在使用风力作为 motion vector 绘制室内场景时会有 leaking 的问题,于是制作组存了一个 velocity magnitude volume 去解决。
notion image
最后介绍的是 Scattered Light Volume,通过采样 material 和 shadow volume 生成,存储了所有直接光(日光和 Local Light)和环境光(通过采样之前提到的 irradiance probe gird)的散射光强度。用于在 accumulation pass 中去计算 in-scatter 和 transmittance。
notion image
这里没有使用 Temporal,取而代之的是用 dithered lookup 和 TAA 的方法。主要原因是光源移动时会产生光源的残影,同时对于一些密度较大的 volume 当相机移动时也会产生拖尾。
notion image
上面介绍了游戏中的整个 froxel,然而由于 volumes 的大小有限,对于一些高频细节难以实现,使用起来精度也不够,于是制作组选择了同时采用 Raymarching 的方式。
notion image
Ray length 通过 depth buffer 和 ground plane 以及 cloud dome 求交结果计算得到。为了减少计算开销,用了地平线在 15 年分享的做法,每次和 cloud 相交时,都会二分步长,然后从中点出发继续迭代,通过不断的重复直到达到预先设定好的 i_max 次数,然后按照这个 step size 继续迭代下去。下图也可以很清楚的看到 raymarching 的步长。
notion image
从 froxel 结束的位置开始做发出光线,根据 blue noise 做偏移。Target resolution 只有屏幕分辨率的一半,然而即使这样开销还是很大,于是将 reconstrction 分散到了 4 祯去做。
notion image
下图一系列都是做 reconstruction 的方法,这块比较复杂先搁置以后补上,建议去看原文。
notion image
notion image
notion image
notion image
最终需要将半分辨率的 frame 拉伸到全分辨率,使用的做法和 Scattered Light Volume 时一样,用了 dithered 和 TAA,可以看到效果很不错。
notion image
最后的渲染开销统计,raymarching 果然是开销最大的部分。因为所有的实现都是 computer based 的,所以很多都可以 overlap 执行,在主机平台上也能很好的结合 async computer 节省带宽压力。
notion image

Scene Integration

notion image
天空的散射预计算参考了 EA 在 16 年的分享,在此基础上加入了 earth shadow 来提升随 dynamic time of day 的效果。根据时间段更新 LUT,并缓存到一个 volume 里去参与计算后续的 forward 和 deferred lighting。
notion image
为了性能考虑并没有在每个采样点去做,只在 raymarching 之后在 weighted depth 上采。为了突出体积光效果,将 visibility 计算分离出来在 shadowed area 里算,结果随着透射会衰减。
notion image
notion image
在渲染完所有不透明物体后开始渲染半透明物体,将之前得到的 scattering light volume、raymarch 与天空的 scattering/transmittance 拿来参与计算。这里还会用到 Cirrus cloud layer 作为密度的 lookup,除此之外和之前云的 shading model 一致。
notion image
结合起来的渲染效果,无论是近处还是远处细节都无可挑剔。
notion image
天空的环境光,晴朗时候蓝色的天空就是用这个实现的。用了一个 32x32 大小的 probe 去采,每 256 平方米摆一个。得到的光照采样结果用于在该方向上的瑞利 / 米式散射计算中。
notion image
notion image
为 Sky Irradiance probes 部分做的优化,visible probe 采样光线更多,但是也不能忽略 invisible probe。采样时用了大步长,而且没做 refinement。
notion image
notion image
reflection cube 使用了一个低分辨率的的 cube map 去存 in-scattering 和 transmittance。为了降低开销,raymarching 采样部分同样和 sky irradiance probe 做法一样。
notion image
水的反射混合了 SSR、reflection probe、planar reflections 和 height map tracing,因为使用的分辨率不高,最终开销也很低,同样 raymarch 时也用了 temporal blend 来做 trick。
notion image
notion image
最终的总结,非常清晰的架构思路。
notion image
未来的一些改进方向,比较期待 volumetric shadows 和 wavelength dependent transmittance….
notion image
感谢 R 星的 graphics and lighting team 以及娜姐 (这几年 SIGGRPAH 都是她主持了
notion image

References

这里我直接找出了各个 ref 的链接,方便查找
Applied Graphics Research for Video Games(娜姐当年在 I3D 上的经典 talk)
Low Complexity, High Fidelity - INSIDE Rendering (感觉 Playdead 他们组的技术力很强… 虽然做的游戏看上去规模不大)
Improved Culling for Tiled and Clustered Rendering (COD 组的 talk,和剔除相关)
notion image

个人感想

去年我自己在玩大表哥 2 时,就惊叹于其自然环境渲染的逼真,做任务赶路时也经常会停下来看看风景。今年 Siggrpah 得知他们来分享后,第一时间就下了 Slide 分析他们的做法,看着看着就做了不少笔记,于是想着干脆发出来分享一下,也可能对其他人有些参考意义。不过由于我水平有限,感觉一些细节的地方理解很不准确,也欢迎各位看了原分享后有什么不同的看法指出来让我改正。 > 本文由简悦 SimpRead 转码