《荒野大镖客救赎2》天气系统开发过程中的技术细节

《荒野大镖客救赎2》天气系统开发过程中的技术细节

《荒野大镖客2》作为去年最佳叙事和最佳表演的得主,在环境氛围的渲染和角色动画上都展现出了无与伦比的效果。 而它的天气系统也为游戏中的故事情节增色不少,让玩家在享受游戏的同时,也能深刻感受到第二次工业革命时代美国西部的氛围。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

Red Dead Redemption 2 拥有我在次世代主机上见过的最佳画面

今年SIGGRAPH R星也来分享了Red Dead Redemption天气系统开发过程中的一些技术细节。 看完觉得干货很多,于是自己做笔记,供自己学习参考。 由于本人经验不足,加上分享中的一些技术细节与自己的项目关系较大,部分翻译和理解可能不准确,欢迎大家在评论区提出。

原文链接/s2019/slides_public_release.pptx

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

首先说一下游戏的整体风格目标和参考。 Red Dead Redemption 2 是原始故事的前传。 它发生在 18 世纪中叶。 当时美国西部的城镇还很少,所以自然风光成为了比赛的主体,球队也功不可没。 于是找了很多当时的山水画作为参考。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

地形参考

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

体积云

首先,大致解释一下什么是基于物理学的体积散射模型,当光射到体积的粒子上时,一部分会被吸收或反射。 朝向相机位置散射的光子在光路上是内散射,而其他方向的光子是外散射,这也会影响其他物体表面或粒子的光照。 这两部分的算法与下图中公式中的P(Phase function)有关。

这通常被称为多重散射。 通常,为了简化模型,只考虑参与透射的外散射部分(透射率)。

对于每一个粒子,它的散射光计算可以分为Visibility和Phase function。 具体的Phase函数后面会提到。 在这里UI界面,很高兴知道它是一个概率密度函数。

透射部分的计算采用比尔定律的指数衰减函数,它描述了光通过体积介质的强度,并受体积本身的消光系数影响。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

Integration是最终的光照计算公式3D道具,可以看出它包括emission、scattering和transmittance

这里有EA在Siggraph的15年分享,可以看出是同一套光照模型。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

设计理念尽可能接近现实中的物理效果,实现了支持各种天气效果的系统。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

整个系统的结构分为三大块。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

数据模型

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

Cloud Map的RG通道分别存储两个云层,分别通过mask和noise map生成,同时受游戏中的天气和时间参数影响

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

Cloud Height Map,RGBA8 存储基于高度的形状信息来改变云和雾的高度。 Red Dead Redemption 支持层云和积云,采样也受天气参数影响。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

Cloud Detail参考Horizo​​n在2015年分享的做法,在xy和xz方向对2D位移矢量图进行两次采样,然后根据环境中的风力得到3D噪声LUT中的贴图。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

贴出代码后,可以清楚的看到他们的云方式。 这里可以看到Cloud Height Lut的z通道也是用来控制噪声变化强度的。

float2 c = SampleCloudMap(ray.p);
float3 cloudLut = SampleCloudLut(altitude);
float density = smoothstep(g_CloudShape.xz + cloudLut.xy, g_CloudShape.yw + cloudLut.xy, c.xy)
float rescale(vMin, vMax, v)
{
return saturate((v-vMin)/(vMax-vMin));
}
density = rescale(noise, CloudLut.z, density);

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

根据云图,也可以实现这种雨汽效果

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

Localized Fog是通过Fog Map实现的,它像Cloud Map一样覆盖了游戏中的所有可玩区域。

Fog Map的三个通道分别存储了雾的起始高度、衰减距离和密度,产生时也受天气和时间的影响。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

全局高度雾和局部雾的组合效果在屏幕上提供了良好的体积感。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

局部雾的另一种实现是让艺术家在场景中放置雾体积。 基本原理是粒子配合 alpha 混合或添加剂。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

渲染

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

他们使用了和Guerrilla一样的坚果壳结构,近处使用froxel,远处使用ray marching。 具体型号可以看他们在Eurographics 2018的分享。

Nubis:简而言之实时体积 Cloudscapes:///#ie=UTF-8&wd=/read/nubis-realtime-volumetric-cloudscapes-in-a-nutshell

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

Shading Model:解释一下前面的公式,P代表相位函数,L代表亮度,V代表能见度。 注意这里说的是用两束光octave来估计multi-scattering,下面的公式有详细解释。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

Phase Function:描述给定波长的光被粒子以不同角度散射的现象,即光子的概率密度函数。

Red Dead Redemption 2中使用了Henyey-Greenstein相位函数(下图中的HG),g为各向异性值,存储在材质体积中。 但传统的HG只对haze等强散射体有效,不能很好地进行多重散射和后向散射,需要改进。

可以看到这里在计算phase function的时候,使用了多个HG function累加来计算multi-scattering的效果,使用weights让美工改变效果。 最后只用两个八度来累加演奏。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

然而,效果仍然缺少后向散射部分,所以这里是对最终结果的假效果。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

后向散射也受消光系数的影响

最终的结果很棒unity爆炸粒子效果,它会随着天气和一天中的时间而发生很大变化。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

Visibility:这里主要通过shadow map获取物体的可见性。 对于云,将对主光源(太阳或月亮)的消光进行额外采样,以获得更高频率的阴影。 采样距离还受天气和时间参数的影响。

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

Terrain Shadow Map是通过对地形的高度图进行raymarching得到的。 得到的地图为RG16F,分别存储射线相交时检测到的地形高度和Ray Length。 然后将R通道的Intersection height与terrian shadow map进行对比,得到最终的visibility结果。 射线长度可以用来调整比较阈值,以提高软阴影效果。

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

Cloud Shadow Map使用ESM存储直接光照和阴影(如果你不知道什么是ESM,可以到下面的链接阅读Nvidia的这篇文章),它的深度是通过从光源到cloud,结果会被 blur 存储在 mip map 中,以避免出现锯齿。

高级软阴影贴图 /presentations/2008/GDC/GDC08_SoftShadowMapping.pdf

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

对于 Ambient Light,这里的 Visibility 重用了上面 cloud raymarch 的结果。 远距离 raymarch 渲染将对低分辨率抛物线纹理进行采样并执行平行缩减。 对于附近的frustum物体,直接使用烘焙的Irradiance probe filed,里面存储了计算需要的光照信息。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

Local Lights的方法比较节省性能,直接通过对光簇体积进行采样得到。 可见性也是通过阴影贴图完成的。 出于性能考虑,仅使用一个HG函数来计算单次散射模型。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

Rainbows的具体方法就不多说了,直接在体积中调整雨水密度即可生成(下面材质体积会说)。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

Lightning(闪电,初见时理解为照亮QAQ)比较简单粗暴。 每一次闪电都会生成一个点光源到一个列表中,然后迭代计算每个点光源。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

场景中的散射光源大概就是这些。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

以上就是如何计算物体表面某个采样点的散射光。 接下来介绍如何管理场景中的渲染对象。

上面说了,附近的物体会被froxel管理。 一般由平截头体空间形成的体素大小为160x88x64,但在一些室内场景中会适当缩小。 最后,生成了三个裁剪空间体积。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

转贴之前EA的分享,作为参考和对比

Shadow Volume采用R16F格式,存储了所有直接光照的阴影信息,包括CSM、Cloud shadow map和Terrain shadow map。 这里还使用了时间滤波来解决高频阴影细节的欠采样。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

Material Volume比较大,分为两个Sub Volume:

第一卷存储散射系数和吸收系数,第二卷的R存储相函数中使用的各向异性值,G存储全局发射值(这里提到不支持每体积发射雾rendering pipeline ),B通道存储环境强度,主要用于室内ao效果,最后一个A通道是前面提到的雨密度,用于调节彩虹效果的强弱。

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

在 Material accumulation pass 中,对所有材料进行采样和混合。 顺序是先做alpha additive,再做alpha blend,这样更容易做一些城镇建筑的细节。 为了支持室内不同的粒子效果(如火、冒烟、爆炸等),将粒子放到最后计算。

这里也提到,所有的物质来源都是利用噪声进行耕作,并受到风的影响。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

与阴影体积一样,时间过滤也用于此处的第一个子体积。

这里也提到了用风力作为运动矢量来绘制室内场景会存在泄漏问题,所以制作组保存了一个速度量级体积来解决。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

最后介绍的是Scattered Light Volume,由采样材质和阴影体积产生,存储所有直射光(太阳光和Local Light)和环境光(通过采样前面提到的irradiance probe grid)的散射光强度。 用于计算累积过程中的散射和透射率。

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

这里没有使用Temporal,而是使用dithered lookup和TAA的方法。 主要原因是当光源移动时,会出现光源残像,而且对于一些密集的体积,相机移动时也会出现拖尾现象。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

上面介绍了游戏中的整个froxel。 但由于体积有限,一些高频细节难以实现,精度不够,所以制作组选择同时使用Raymarching。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

射线长度是通过与深度缓冲区、地平面和云穹顶相交来计算的。 为了减少计算开销,使用了15年地平线共享的方法。 每次与云相交,步长一分为二,然后从中点继续迭代。 重复直到达到预设的i_max次数,然后继续按照这个步长迭代。 下图也可以清楚的看到raymarching的步长。

地平线的实时体积云景:零

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

光线从froxel结束的位置发出,根据blue noise做offset。 目标分辨率只有屏幕分辨率的一半,但即便如此开销仍然很大,所以重建被分配到 4 帧。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

下图展示了一系列的重构方法。 这个比较复杂,以后再补充。 建议阅读原文。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

unity粒子效果一样_ae粒子效果和爆炸效果_unity爆炸粒子效果

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

最后,需要将半分辨率帧拉伸到全分辨率。 使用的方法与 Scattered Light Volume 相同。 使用了抖动和TAA,可以看出效果非常好。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

在最终的渲染开销统计中,raymarching确实是开销最大的部分。 因为所有的实现都是基于计算机的,所以很多可以重叠执行,也可以和宿主平台上的异步计算机很好的结合,节省带宽压力。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

场景整合

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

天空散射的预计算参考了EA在2016年的分享,并在此基础上加入了地球阴影,提高动态时间效果。 根据时间段更新LUT,缓存在一个volume中,参与后续forward and deferred lighting的计算。

/s2015/The%2520Real-time%2520Volumetric%2520Cloudscapes%2520of%2520Horizo​​n%2520-%2520Zero%2520Dawn%2520-%2520ARTR.pdf 中基于物理的天空、大气和云渲染

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

出于性能考虑,不是在每个采样点都做,而是只在raymarching后的加权深度做。 为了突出体积光效果,visibility计算被分开计算在阴影区域,结果会随着透射衰减。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

渲染完所有不透明物体后,开始渲染半透明物体,利用之前得到的散射光量、raymarch、sky scattering/transmittance参与计算。 这里也会使用Cirrus云层作为密度查找unity爆炸粒子效果,否则与之前的云着色模型一致。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

组合渲染在近景和远景细节方面都无可挑剔。

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

天空的环境光,晴天时蓝天以此实现。 使用32x32大小的探针进行挖矿,每256平方米放置一个。 生成的光照样本用于该方向的瑞利/米特散射计算。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

对于Sky Irradiance probes部分的优化,visible probe采样到的光更多,但是invisible probe也不能忽略。 使用大步长进行采样,没有进行细化。

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

unity爆炸粒子效果_unity粒子效果一样_ae粒子效果和爆炸效果

反射立方体使用低分辨率立方体贴图来存储内散射和透射率。 为了减少开销,raymarching采样部分也和sky irradiance probe一样。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

水的反射是SSR、反射探头、平面反射和高度图追踪的混合体。 因为使用的分辨率不高,所以最终的开销也很低。 同样,temporal blend 也用于 raymarch 中的 trick。

unity粒子效果一样_unity爆炸粒子效果_ae粒子效果和爆炸效果

ae粒子效果和爆炸效果_unity粒子效果一样_unity爆炸粒子效果

最后的总结是一个非常清晰的架构思路。

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

对于一些未来的改进方向,我期待体积阴影和波长相关的透射率......

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

感谢Star R的图形和灯光团队和娜姐(她在近几年主持过SIGGRPAH

ae粒子效果和爆炸效果_unity爆炸粒子效果_unity粒子效果一样

参考

这里我直接找出每个ref的链接,很好找

unity爆炸粒子效果_ae粒子效果和爆炸效果_unity粒子效果一样

个人想法

去年自己玩《大表哥2》的时候,就被它逼真的自然环境渲染惊艳到,经常在路上做任务的时候停下来看看风景。 今年Siggrpah得知他们要来分享,立马下载了Slide分析他们的做法,看了之后还做了很多笔记,于是想着发出去分享,或许也有一定的参考价值给别人。 但是由于本人水平有限,感觉有些细节的理解很不准确。 也欢迎大家看完原分享后有什么不同的地方指出来让我指正。

来源知乎作者:佛罗伦萨木笛·育碧(Ubisoft)·技术美工