前言
在之前读过一个介绍体积云的系列,当时是介绍的《地平线:零之曙光 》中的体积云方案。当时Guerrilla(游戏的开发工作室)的方案还是以在地面看天穹的云层为主要实现目标,在PS4上实现了不错的效果。
随着续作及其DLC的陆续发布,开发组对于体积云在更多场合呈现更丰富的样态有了思考与实现。这篇分享的主讲人Andrew Schneider本身是一个大气渲染方面的专家,有着十年以上体积云渲染的研究与经验。
文章还是以翻译原文的讲稿为主,并且由于原文的篇幅很多地方较长,会进行适当的精简和概括。由于图文内容量都很大,这次会分为上中下三篇,打星号的部分则是我个人的补充说明。
1 前导介绍——A Brief (Nubis-Centric) History of Cloud Rendering
*这部分如标题所述,主要是介绍了作者自己(以在Nubis系统中开发的为主)的体积云渲染履历与技术路线——Nubis是他们这套体积云系统的名称。
*这一段作者主要回顾了2011年的一篇论文内容,其中介绍了当时用于动画Rio的离线渲染体积云技术。这个当时被称为SmogVox的技术是他的同事Trevor Thomson开发的,由于用到了光线追踪技术,在离线状态下渲染1920x1080的分辨率大约需要4-10分钟一帧。
我(作者)于2014年加入了guerrilla,当时负责改进游戏《Killzone》中使用的2D天空盒。
一开始,我试图以移植离线渲染中用过的那套体积算法来解决云形体的问题。
我构建了一个自定义的流体生成器(fluid solver,直译是求解器)——昵称是Aero,使用了在Houdini被称为micro solvers的子系统。
Micro solver是Houdini计算一帧中的流体模拟的模块化方案,允许使用者重排、修改、引入新的解,以及进行更多你需要的定制(如图)。
作为与更流行的燃烧样式(combustion-style)生成器的对比,Aero是流线式(streamlined)的并在云体积逐步增大方面进行了强化。(*参考GIF)
回到2014年,我们模拟了几种不同云的形体并尝试了不同的渲染方案,但它们都无法适应PS4的性能需要,因而无法用于当时的游戏前作《地平线:零之曙光》。
当时时间不足了,因此这项研究工作(流体体积云)就被搁置了,我们转而进行开发。
我们开发了多种不同的建模和渲染方式——可以视为是一种2.5D的云,因为渲染这些云的数据不是通过3D的体素数据,而是2D纹理数据。我们把这一云层系统称为Nubis,下面我们回顾一下这个系统是如何运作的。
*这部分细节其实当时介绍2015年的那篇体积云实现中比较详细的介绍了。
*图中简要回顾了一下这个系统不断进行增量开发进化的脉络,以及相关的分享内容。
What made Nubis successful in our games was the ways in which we compressed our cloudscapes and added density and lighting details, which are specific to clouds, at render time while fine tuning a rendering technique known as volumetric ray-marching. This allowed us to model cloud evolution and time of day cycles which, in addition to producing distant clouds, could produce superstorms with red lighting, and some low altitude fog-like clouds that the player could fly through. Our method of ray-marching turned compressed cloud models into rendered frames of clouds in between 0.2 and 5 milliseconds depending on if we viewed them from afar or we if flew through them.
使我们的Nubis系统得以成功的是,我们压缩了云的形状并添加了密度和光照细节——参数与具体云的种类相关,并通过微调后的被称为体积光线步进(ray-marching)的技术进行渲染。
这使得我们能对云的光照进行建模,并模拟出一天中不同时间的光照效果——除了产生远距离云层的视觉外,还能产生有着红色闪电的风暴,或是部分玩家可以穿过的低海拔雾状云层。
我们的ray-marching方法将压缩的云模型渲染成体积云需要0.2到5毫秒,取决于玩家的位置是远远地望向云层还是从中飞过。
让我们简单看看这些建模和渲染方法是如何起作用的。
在一个ray-march过程中,一旦确认像素中包含了云层,就需要执行以下步骤:
- 沿着射线与云层的顶部和底部相交的部分逐步执行计算。
- 对于每一步(云层中)的采样点,采样密度和光照——这需要第二次的(比较昂贵的)朝向光源的ray-march过程,之后将这些数据累加到前一步的结果数据上,为每个像素计算颜色和透明度数据。
- 重复这一步直到像素变得不透明(full opacity),并且云体积内的每一个像素都需要执行这一过程。
让我们看看每一个步骤执行时的具体过程,从ray-march算法的核心——采样密度开始。
这里我会集中回顾两种我们使用过的云渲染方法,两者都直接影响了我们体积云渲染的路径:
- 第一种被称为垂直轮廓法(Vertical Profile Method),用于高海拔的对流层的云(玩家无法抵达的)
- 第二种是封包法(Envelope Method),我们用于玩家可以抵达的山岳云层。
两者有其各自的密度采样方法,但共享一些类似的设计思路。
那些被我们称为Nubis数据场(Nubis Data Fields,缩写NDF)的2D数据场,包含了云在compute shader中渲染的指令——用于从中“解压缩”得到3D云的过程数据。
这些2D数据场覆盖了我们地图16km的区域,在渲染时从中采样以构建3D云的形体。
两种方法的ray-march步骤最终都构建了一个高精度的3D体积(如图)——从一个低精度的空间轮廓(dimensional profile)开始。
虽然可能看起来有些相似,但构建这些空间轮廓的方式实际上(在不同方法中)有所不同。
在垂直轮廓法的例子中,我们从5个2D的NDF开始:
- 云层的最小、最大高度定义了云的垂直范围。
- 顶部类型和底部类型定义了垂直轮廓的两个查找纹理(lookup textures),两者相乘就得到了我们称为垂直轮廓的数据。
- 然后,我们通过覆盖率数据来缩放这个垂直轮廓,以控制云形成的位置。
在封包法的例子中,我们从4个2D的NDF开始:
最小、最大高度
定义了封包云层的渲染范围。而空间轮廓是三个梯度的乘积:
- 一个指向下方的顶层梯度
- 一个指向上方的底层梯度
- 一个从外向内的边缘梯度
我们使用了3D噪声来侵蚀前一步的空间轮廓,并“超精度”至最终看到的结果。
我们研发了被称为Perlin-Worley噪声的纹理来模拟纤细的和波浪状(wispy and billowy)混合的细节,并单独使用Worley噪声来模拟波浪状的细节。
These were combined in various ways per model to create what we called noise composites for potential wispy and billowy details at the sample position.
它们在不同的云模型中有不同的混合方式,以创造被称为噪声组合的效果——用于云层采样位置中的(潜在的)纤细和波浪状细节。
之后我们使用类型数据(Type data)以混合纤细到波浪状的噪声。
The erosion was modeled as the subtraction of the inverse of the dimensional profile from the noise composite.
云的侵蚀效果建模自:噪声合成减去空间轮廓的反相。
“Pseudomotion” was simulated for both models by animating the noise in the wind direction.
“伪运动”(Pseudomotion)是通过按风的方向执行噪声动画来模拟的。
在采样完密度后,我们采样光的强度。
两种方法都依据以下3项来定义光的能量:
- 直接光散射,代表所有从太阳入射的光能量。
- 环境散射,代表从天空和相邻云层来的光能量。
- 次级散射,代表从其它来源(例如光照)中来的光能量。
计算这些能量有着不同的方式。完整的讲述在2022年的讲座中,而现在我会简要概括一下。
给定采样点的直接光散射的计算,是通过一个包含3项概率的公式:
- 传播系数、散射相位以及多重散射(Transmittance, Scattering phase, and multiple scattering)。
- 传播系数用来度量光学介质中给定深度的光量。图中展示了随着云层中的深度增加,光是如何递减以及被吸收的。为了收集这一深度,你还需要传导(conduct)一根(非常昂贵的)光步进射线朝向光源。
- 散射相位用来度量给定采样位置的能到达人眼的能量——基于给定的视角向量和光照向量。云中的光线散射是由于其中的微小水滴或冰晶。光线在云层中的散射有着延路径增加的趋势,因而我们使用Henyey Greenstein相位函数来实现这一效果,综合了艺术家导向和物理现实。
- 多重散射描述了光经过水分子(molecules)多次折射后,散射进入我们的视角向量的光量。我们使用空间轮廓作为概率场的基,以描述你在云层中时(随着深度增加)内散射(in-scattering )逐渐变多的趋势。我们使用另一个beer-lambert衰减曲线来计算光线被吸收导致衰减的程度——这一衰减也考虑了云层下方会有相对更少的光散射入云层的事实。
最终,我们缩放这一相位函数来确保它的方向性。
这里展示了没有多重散射估算(上图)和添加了这一估算的不同效果。
为了估算射入云层的环境光(不使用光线步进),我们再次将这一几何描述建模成了概率场。
主要的环境光来源自上方和周围,并渗入(penetrates)云层表面。
空间轮廓已经提供了云的从外向内的梯度,我们使用它的反相来创建一个梯度——以描述一个环境光到达云层内某点并散射进我们眼睛的概率。
这里展示了一组对比:上方是只有直接光能量的结果;下方是综合了直接光和环境光的结果。
最后考虑次级光照能量。通常来说,对于任何放置在云层内的光源来说,每次采样都需要昂贵的光线步进计算(向光源)。图中的例子就需要追踪3根步进射线——而这不是一个理想方案。
再一次,我们把这建模成概率问题。
我们建模了一个光体积,以估算光源周围每个采样位置的光能——在主采样步进射线(primary ray-march)上进行。其中有更多细节,不过后面我会展开解释它是如何作用于我们的体积云。
这里展示了基于这一计算,游戏中云层风暴呈现的效果。(*红色闪电作为次级光源)
The next step (pun intended) is to determine the step size for our march so that the next sample can be placed along the ray.
下一个步骤是确认射线上采样的步长。
*这里的step,作者标注是pun intended——双关语。有点程序员冷笑话的意思了。
垂直轮廓法采用了一种自适应的步长,它随着到摄像机的距离逐步增加。这样越远处(需要精度越低)的位置采样数就越少。
图中的局部天空需要大概半毫秒来渲染,而全屏整体的天空则需要大约2.2毫秒。
然而,为了支持能以飞行的方式穿过封包法渲染的云层——它们都距离摄像机很近,因而需要很多采样数,我们不得不发挥一些创造力(get a bit creative)来避免过多的采样。
我们混合了两种分别被称为Cone Step Mapping和Distance Step Mapping(直译是锥体步进映射和距离步进映射)的方法,以便仅仅依据高度数据就能高效地放置采样点。
当计算光线步进时,我们基于(前一步的采样点垂直)和表面的交点生成一些锥体,并计算和这些锥体的交点以确认命中云层之前的最大可能步长。而距离步进映射被用于确保,不在云层外的区域消耗太多采样点。
*这里原文没有描述出锥体追踪是一个迭代的过程,从图中可以看出,是循环执行步长减半+锥体求交点的过程,直到命中云体。
当我们开始在封包云层内部采样时,我们开始采用小的步长来采样实际的云层密度。
图中你可以看到采样的位置——以红色点显示出来,我们集中采样云及其周围的空间,而在空白处则没有那么多的采样点,显然这是更好的一种分布方式。
这种采样能提升多少性能呢?不进行优化之前,开销是4.2毫秒。
在优化后的时间是1.3毫秒。
使我们的云系统进一步提升其性能表现的一个方式是,改进逐像素进行ray march的现状(使用一定的超采样)。两种方式都对云的渲染有加速作用。
垂直轮廓云使用了分时超采样技术,将渲染的开销分摊到了16帧中。(*原文用了Amortizes ,分期偿还一词)
对于远处的云,它能使原本需要20毫秒的渲染效果在一帧内以2毫秒的速度(分帧)完成;但对于近处的云这种方式是不解决问题的,因为摄像机会快速移动。
因而,对于置身之中的封包云层,我们采用了如下方式:将渲染过程分到两个pass中,靠近摄像机处使用昂贵但低清晰度的渲染模式,而较远处我们希望能减少走样。
至此,我们已经覆盖了之前的一些云建模与渲染的方式。让我们把两种方法做个对比:
- 在封包法中我们不真的支持演进式推算策略,因为没有额外生成锥体和距离场的性能预算。(*图中标注出了 Pseudomotion Only,只支持伪运动,前面提到过的一个词)
- 两种方式都是全天候有效的。
- 光照只在垂直轮廓法中实现了。
- 但两者都支持高帧率模式。
- 只有封包云层是支持飞行通过的。
And unfortunately, none of these methods are very visually intuitive to author and work with. Let’s be honest. Those of you who have worked with these methods know what I mean.
不幸的是,两种方式都不是以符合视觉直觉的方式来制作起效的——实话实说,负责以这些方法制作云的人知道我在说什么。
两种方法中的这些问题都阻止了我们(包括艺术总监)实现最初就想实现的目标——飞越云层。
因而,在完成了西之绝境的版本开发后——怀着既沮丧又基于证明自己的心情,我开始开发一个原型。在上一年的分享中,我以这一技术的简短一瞥作为了收尾——被称为实时体积云渲染(real-time voxel-cloud renderer)的原型。
2 体积云渲染原型——A Multi-Voxel Cloud Renderer Prototype
相比于在不确定云在何处就开始ray-march采样,我把一个包围盒和内部有向距离场整合到了原本采样来源不可知的方法中。
将采样了密度和光照的多个体积叠加。图中展示了3层叠加的体积云效果。
图中白框范围展示了这种混合式采样放置方法。
我独自尝试迭代了很多版,直到这一过程(在我个人角度)无法优化得更快为止。
至此好消息是我们可以组合少量的云层,允许玩家飞进其中(之前只能环绕),在PS5的960x540分辨率下需要4毫秒的开销。
而不好的——但极度偶然的消息是,因为我把这一结果展示给了艺术总监,现在他让我回忆起了加入Guerrilla最初就定下的目标。
很快,我就被召集参加了DLC的预告片的会议——听说展示的内容需要包含一些云层的技术。
*截至到原型这一步其实性能还是比较极限的。
3 燃烧海岸中面临的困难——The Burning Shores
图中,预告片中这一幕需要的云都被以白色椭圆体表示了——不止是云层,还需要能高速飞过前景和背景中可见的各处有着波涛状细节的云层。(*原文这里也配了一段视频,展示了主角的飞行)
在会议后我执行了一次测试,以确认原型在这种使用条件下的性能表现——性能很糟糕,并且细节也不够好。
幸运的是,我们得知了燃烧海岸DLC会只发布在PS5上,这会为我们减少一些性能上的限制。
之后我和两位技术主管Jeroen Krebbers和Nathan Vos讨论了我们从原型变为可交付版本的可行性。说实话这是一次激烈的讨论——出于好的目标。
会议最终确定了一件事,就是如果我们如果在宣传片中展示了这项效果,我们就需要在游戏中实现它。
我们也认同如果它无法实施,那么整个企划就都会宣告失败。在几位同事的帮助下(*原文列出了具体名称),我们确信了视频中展示的效果可以最终优化并无损地加入DLC中。
*这里作者展示了对应的宣传片,视频容量太大这里就不放了。
A few takeaways from that experience: I think it was when I was able to produce an expansive cloudscape with this much variety for this shot, that I realized we had a system that was going to work one way or another.
从这次经验中能总结出一些takeaway:当我能为这个镜头制作出如此丰富的云的形体时,我意识到我们有了一个无论如何都能生效的系统。(*结合后文来看,是指会被项目上以各种方式来使用)
当我们回顾这个镜头时——它在天空一公里的位置,而有人问我是否应该用云掩盖住200米高的山顶。艺术总监说“不,留下它”。这使我意识到我们最初的目的,在实际创造某种效果面前或许又没那么重要了;我也意识到艺术总监已经开始使用云系统来作为前景工具,以构建视觉深度了。
同时,当我们观看了宣传片的观众反馈后,发现人们提到了云的效果,但没有任何关于它和实际游玩相结合的讨论——意味着大多数人还只是把这当成一个电影级宣传片。
这让人感到既兴奋又有点害怕。
燃烧海岸DLC自身背景被设定在洛杉矶的火山群岛废墟。
True to Hollywood, the goal of the project was to deliver bigger than life experiences.
正如好莱坞(的口号一样),游戏的目标也是提供一段大于生活的体验。
自然地,结合正在开发的新技术,我们希望为玩家打开天空的探索——而不止是把它局限在转场动画中使用。
这意味着云系统不仅要起到之前的细节体积天空盒的作用,玩家要能无缝地从云上飞入水中。
然而,后来的结果表明,要实现这一效果有着更大的挑战——比宣传片中的更大。
*这一段因为有多段播片,可能直接翻译作者的演讲稿会觉得略微缺少了一点上下文。其实作者主要面临两个问题,一是宣传片的体积云效果,其技术当时没有达到实机的标准;另外是它们想让玩家能快速无缝飞过大世界中的云层,又增加了一些优化上的难度。
结语
Guerrilla的云系统已经标号到了第3代了,这篇分享的作者也无疑是一个专项领域的特型人才。读了很多有具体实现愿景的渲染文章,我发现无论硬件如何发展,游戏开发者在新平台或新项目中想拿出的视觉效果都是有挑战的(例如之前读的超凡蜘蛛侠系列的建筑LOD,他们就是想在城市建筑的呈现上有所突破)——当然一般来说游戏产品也要取得一定的市场或商业成绩,并确实有符合预期的性能表现,才能在SIG这样层面的大会上去演讲。
这篇分享由于图文都很长,这次算是读完了承前启后的部分。下次的中篇会从第三代云的数学建模开始,逐步深入细节。
最后是资料链接:
Nubis3: Methods (and madness) to model and render immersive real-time voxel-based cloud 1080P PPTX PDF