前言
在发布《地铁》系列的最后一部游戏之后,我花了几个小时研究其内部作品,并决定分享一些从技术角度看可能很有趣的东西。 我将不进行详细的分析或研究着色器的反汇编代码,但我将展示开发人员在创建游戏过程中做出的高层决策。
目前,开发人员尚未谈论游戏中使用的渲染技术。 唯一的官方信息来源是
GDC报告 ,该
报告在Internet上其他任何地方都找不到。 这很烦人,因为该游戏运行在非常有趣的专有引擎上,该引擎是从以前的Metro系列游戏演变而来的。 这是最早使用
DXR的游戏之一。
注意:本文不是完整的描述,如果发现值得添加的内容,我将再次进行介绍。 也许我错过了一些东西,因为某些方面仅在游戏的下一阶段出现,或者我只是看了细节。
第一步
我花了几天的时间才能找到一个可以使用此游戏的环境。 在测试了多个版本的RenderDoc和PIX之后,我开始研究使用Nvidia NSight进行光线跟踪的结果。 我想学习没有光线追踪的渲染,但是NSight也允许我探索此功能的细节,因此我决定继续使用它。 对于其余的渲染,PIX非常适合。 屏幕快照是使用这两个应用程序拍摄的。
NSight有一个缺点-它不支持将捕获的内容保存到文件中,因此我无法返回正在研究的框架。
在工作的一开始,我还遇到了另一个与框架调试应用程序无关的问题:光线跟踪功能需要安装最新的Windows更新,但是游戏允许将它们包括在选项中,而无需安装更新。 在这种情况下,包含功能会导致游戏在启动时崩溃。 GeForce Experience还没有提到需要正确版本的Windows来启用这些功能。 这个问题需要双方都解决。
为了完整起见,我从运行有最大可能参数但没有DLSS的游戏中捕获了图像。
框架分析
成品框对渲染的简要分析显示了相当标准的一组功能,但通过光线跟踪(光线跟踪GI)执行的全局照明除外。
在渲染图片之前,在计算队列中减小前一帧的比例,并计算平均亮度。
图形队列从渲染变形粒子(相机上的液滴)开始,该粒子在后期处理阶段应用。 然后快速进行深度的初步遍历,在Gbuffer的前面创建了一部分深度。 看起来它只是一种解脱。
GBuffer传递根据下图填充4个渲染目标,并完成深度缓冲区的填充。
1.以RGBA8格式作为目标,在Alpha通道中具有反照率和环境光遮挡; 在某些表面上看起来很暗。2.以RGB10A2格式作为目标,并具有法线,并可能在alpha通道中具有次表面散射蒙版。3.以RGBA8格式作为目标,并带有其他材料参数,可能是alpha通道中的金属性和粗糙度。 奇怪的是,在这种情况下,RGB通道包含完全相同的数据。4.使用RG16F格式的2D运动矢量作为目标。深度完全填充后,将构建线性深度缓冲区,并且其比例会减小。 所有这些都在计算队列中完成。 在同一队列中,缓冲区中填充了类似于定向照明的内容,而没有使用阴影。
在图形队列中,GPU跟踪全局照明的光线,但是我将在下面详细讨论。
计算队列计算环境光遮挡,反射以及类似于边缘识别的内容。
在图形队列中,将四阶段的阴影贴图渲染为大小为6k * 6k的32位深度贴图。 在下面的更多内容。 完成定向阴影贴图后,由于未知原因,第三级联的分辨率降低到768 * 768。
在阴影渲染过程的中间,有一个奇怪的时刻:在通过光照渲染局部阴影之前,对冒名顶替者地图集添加了一些对象(关于
此处可以找到哪些冒名顶替者)。 冒名顶替者缓冲区和局部照明阴影缓冲区也都是6k * 6k纹理。
完成所有阴影后,便开始计算照明。 渲染的这一部分相当难以理解,因为有很多渲染执行一些神秘的动作,因此需要进一步研究。
场景的渲染以前面照亮的对象(眼睛,粒子)结束。 将视觉效果渲染到半分辨率缓冲区中,然后使用缩放将它们与不透明对象合成。
最终图像是通过色调校正和光晕计算(减小然后通过色调校正提高帧的分辨率)获得的。 最后,UI被渲染到一个单独的缓冲区中,并与Bloom合成一起叠加在场景的顶部。
我没有找到要进行平滑处理的部分,因此我将其留待以后使用。
全局光线追踪
有关由raytraced GI执行的全局照明的一些信息。 这种加速结构覆盖了游戏世界的大片区域,可能是几百米,同时到处都保持很高的细节。 它似乎以某种方式流式传输。 加速结构的场景与栅格化场景不一致,例如,下图中的建筑物以栅格化形式不可见。
顶视图在这里,我们可以看到围绕玩家位置的四个图块。 同样明显的是缺少在Alpha通道上测试的几何形状。 树木有树干,但没有树叶,没有草,没有灌木。
近景在特写视图中,可以更好地看到物体的细节和密度。 不同颜色的每个对象都有其自己的下层加速结构。 仅在这张照片中有几百个。
脚下的玩家物品有趣的是,玩家的物品也是加速结构的一部分,但由于某种原因位于他的脚下。
皮肤坏了吗?再次断皮?某些带有蒙皮的物体在加速结构中看起来破碎。 观察到的问题之一是拉伸网格(在孩子的腿上)。 另一个问题导致这样的事实,即带有皮肤的角色的不同部分处于不同的位置。 没有拉伸,但零件彼此分开。 似乎在全局光线跟踪照明中看不到这些,或者至少我在游戏中没有注意到这一点。
大量物体在更一般的平面上,您可以看到加速结构中有多少个不同的对象。 它们中的大多数实际上不会对全局照明的计算结果有所贡献。 在此还可以看出,没有LOD方案。 所有对象都添加了详细信息。 知道这对射线追踪是否有影响(我认为是)会很有趣。
超高LOD,每个刻度和开关均完全建模另一个屏幕截图显示了距离播放器较远的物体的巨大细节。 即使没有纹理,此图片中的每个开关和每个刻度也清晰可读。 我移动相机拍摄该屏幕快照的位置位于距播放器几十米的地方,消除这些细节并不会降低图片质量。 也许使用LOD更新加速结构的成本太高,但是很有可能可以异步执行此更新。 这一点绝对值得更详细地探讨。
渲染方向阴影
渲染阴影的主要部分很简单,不需要特别提及,但是这里有一些有趣的地方。
不可能进行阴影投射的网格阴影贴图中的大量细节似乎使用了错误索引缓冲区的网格似乎像加速结构一样,阴影渲染绝对包含了所有内容。 有些对象几乎不影响阴影贴图,但仍会渲染。 我想知道这是否是由于允许而发生的,还是引擎中没有简便的方法将它们排除在外?
即使屏幕空间中有阴影,有些物体也很难注意到。 渲染它们不需要花费很多时间,但是有趣的是,看看是否可以将它们删除以节省一些时间。
在检查网格时,似乎在阴影贴图中渲染的某些网格具有损坏的索引缓冲区,但是在顶点着色器之后,它们看起来是正确的(PIX和NSight中的结果相同)。 这是我设法找到的最好的例子,但距离唯一的例子还很遥远。 也许这是某种特殊的包装位置?
网格似乎皮肤不好剥皮似乎不仅在加速结构方面引起问题。 有趣的是,它不会导致屏幕上出现可见的伪像。
第二部分
小修改
在上一部分中,我写道GBuffer缓冲区的第三个渲染目标很可能包含金属性,但似乎它实际上包含镜面反射颜色。 起初我看不到任何颜色,也不了解为什么所有三个RGB通道都包含相同的数据,但这可能是因为场景中没有颜色反射。 对于此武器,缓冲区包含许多其他颜色。
我还忘记添加自己喜欢的纹理,这是在研究游戏渲染过程中发现的。 绝对值得一提,因为它证明了游戏开发的混乱性质,而这并非总是可以清除的。
“改善我!”透明合成和抗锯齿
在试图弄清楚半透明缓冲区的分辨率如何提高以及游戏如何执行抗锯齿时,我注意到了一些有趣的东西。 我需要一个对比度更高的场景,以便清楚地看到正在发生的事情。 幸运的是,我设法捕获了一个帧,玩家的武器在两个帧之间略微移动。
渲染透明之前似乎在合成透明度缓冲区之前,该缓冲区已经包含完整渲染的图像,并且由于此帧中没有锋利的边缘,因此逻辑上假设这是前一帧的数据是合乎逻辑的。
合成当前帧的透明度之后在向当前帧添加透明度时,我们可以注意到各个断边。 发生这种情况是因为武器向右微移。 一些云被渲染为透明的,但是它们被修剪到地平线(不透明),因此合成不会更改底部,但是已经使用当前帧的深度缓冲区在前一帧的武器网格上进行渲染。
向当前帧添加不透明度之后在几次绘制调用之后,将执行合成网格和不透明网格。 似乎没有特别的理由按此顺序执行此操作。 将透明缓冲区组合到当前帧的不透明对象的数据中是合乎逻辑的,但这不会发生,并且知道为什么会很有趣。
TAA之后完成整个帧后,TAA(临时平滑)通道对边缘进行平滑处理。 我以前对此已经很感兴趣,因为我看不到平滑发生的位置。 但是我跳过了这一步,因为在此平局电话之后,立即开始了布鲁姆通行证的下采样,而我错过了这一平局电话。
镜头光晕
通常,我不想分析单个效果,但是有很多方法可以实现镜头眩光,所以我很好奇选择了哪个开发人员。
现成的合成物的镜头光晕在大多数情况下,镜头光晕几乎不明显,但这是一个美丽的效果。 在屏幕截图中很难显示,因此我不会为此付出很多努力。
镜头光晕在绽放缓冲区中搜索之后,我发现增加了此效果的绘制调用,结果发现这是在提高光晕分辨率的最后阶段之后进行的调用。 在此缓冲区中,效果更加明显。
几何镜头光晕如果看一下几何图形,镜头光晕非常简单。 在屏幕上创建最终结果至少涉及6个四边形,但是没有一系列较小的四边形越来越接近太阳的位置。 我们可以得出结论,这是一个相当标准的解决方案,尽管有些开发人员直接在渲染目标场景中渲染镜头光晕,而其他开发人员则将效果计算为后期处理。
地形渲染
在所有开放世界游戏中,最有趣的困难之一就是渲染地形。 我认为研究这方面似乎很有趣,但是坦率地说,有些失望。
乍看之下,浮雕的片段看起来像是在进行某种细分。 释放部在移动过程中变形的方式使其合理地假设存在一些额外的位移。 此外,在PC上,游戏会主动使用棋盘格装饰,因此,如释重负地使用它会合乎逻辑。
也许我设置了错误的参数,但是游戏渲染了浮雕的所有片段而没有细分。 对于浮雕的每个片段,她都使用统一的32 * 32网格。 也没有LOD。
查看顶点着色器之后的浮雕片段,您可以看到大多数顶点对合并形成了几乎完美的16 * 16网格,除了一些需要更高精度的地方(可能是由于浮雕的曲率)。 上面提到的变形可能是由于当凸版远离相机时读取凸版高程图的mip纹理而引起的。
光线追踪技巧
现在,每个人都在等待什么。
流数据
目前,任何DXR实施中最有趣的方面之一就是处理数据的方式。 最重要的是如何将数据加载到加速结构中以及如何对其进行更新。 为了测试这一点,我进行了两次拍摄,并比较了NSight中的加速结构。
玩家在船内在第一个截图中,我站在一艘破碎的船内,在这张图像的中间可以看到它。 仅加载最近的对象,但地图边缘的大石头除外。
播放器已移动到该图像的左上角。在第二个捕获中,我从地图的边缘移开,并且更靠近图像的左上边缘。 船和它周围的所有东西仍在加载,但是新对象也已加载。 有趣的是,我无法定义任何图块结构。 可以根据距离和可见性(也许限制平行四边形?)从加速结构中加载/移除对象。 此外,右上边缘已移开,但看起来更细致。 对此有更多了解会很有趣。
救济及其内容
地铁中DXR实施的几个方面:关于地形的出埃及记。
首先,有趣的是,加速结构不包含任何浮雕网格(特殊情况除外)。 这些怪物实际上是在地面上运行的,但是从NSight中的数据来看,您可能会认为它们在飞行。 这对我们提出了一个有趣的问题:全局照明的实施是否可以某种方式考虑浮雕(可能使用高度图和浮雕材料)。
下一刻,我将永远不会注意到救济是否到位。 在NSight中加速结构的关卡开始时,我注意到浮雕下有一些网格。
出于各种原因,美术师经常将调试网格物体放置在关卡下,但通常在发布游戏之前将其删除。 在这种情况下,这些网孔不仅可以保留直到释放,而且还成为加速结构的一部分。
除了上面提到的那些网格,我还发现其他网状网格散布在浮雕下方。 基本上,它们没有什么值得一提的,但是这个很有趣-这是一个站在关卡起点下方的角色。 它甚至有自己的游泳池。
最后,加速结构的最后一个好奇元素是从水平面向外看的单侧网格。 除非它们被认为是双边的,否则它们几乎不可能对比赛的画面做出任何贡献。 即使网格物体是双面的,它们也离可玩区域很远,以至于它们可能只是拉伸加速结构。 有趣的是,它们没有被过滤。 该图像还显示了火车和建筑物之间右下角的“浮雕网格”的特例之一。
皮肤无头
我已经讨论过蒙皮网格化的问题,但是在这个级别上,我注意到了其他问题。
首先,这个怪物在一张图片中同时显示了两个错误,我在上面注意到了。 我仍然想知道是什么导致了他们。
我还注意到,这些小动物(如蝙蝠)在加速结构中没有头。
另一个例子。 注意头部应位于的孔。 我还没有看到头部可见的单个案例。
光栅化模式下的同类生物。
注意,头部清晰可见。这是线框头部映射。总结
今天就这些了。我希望您喜欢Metro:Exodus的内部外观。我将继续探索游戏的渲染,但是除非发现有某些特别的部分会引起人们的兴趣或发现值得分享的内容,否则我不会发布本文的新部分。