DOOM4图形研究

    原文地址 http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/


     由于本人英语水平有限,对于图形学技术领悟有限,错误之处在所难免,读者体谅,也欢迎高手 翻译此篇,

抛砖引玉 。   本文你可以随意转载,但请你最好注明出处,毕竟我翻译也不容易。请尊重一下劳动成果!

                              DOOM4 图形研究



DOOM4图形研究


    DOOM在1993年开创了游戏设计和开发的根本变革,这是一个世界性的现象,

推动了像约翰·卡马克(John Carmack)和约翰·罗梅洛(John Romero)这样的
标志性人物。
    23年后,id Software现在属于Zenimax,所有的原创始人都已经走了,但
    并没有什么能阻挡该公司的所有人才来做出一个超级伟大的游戏。


   新的DOOM(2016)是专利权的完美补充,使用新一代的ID Tech 6引擎。   前Crytek Tiago Sousa在约翰·卡马克(John Carmack)离职后,现在担任首

席渲染程序员的角色。

   在id公司的历史上,引擎源码开源广为人知,新一代游戏引擎,通常几年后会

开源引擎,这通常会导致很好的重制和改造。id Tech 6是否开源,但仍然有待观

察,但我们并不一定需要源代码来了解在引擎中实现的漂亮图形技术。

How a Frame is Rendered(一幁是如何被渲染的)


   我们将在下面的场景中检查玩家攻击由一些拥有的敌人防守的gore nest(戈尔
巢,doom4游戏的地图之一)的场景,首先在游戏开始之前先取得Praetor Suit(doom4的装甲服装)。

DOOM4图形研究

现在发布的大多数Windows游戏不同,DOOM并不使用Direct3D接口,但提供了一个OpenGL和Vulkan后端。

   Vulkan是新的热点,Baldur Karlsson最近在RenderDoc(一个图形调试器,支

持DX12.dx11,Opengl)中增加了支持,DOOM4是一个很困难的的选择。使用Vulkan 

运行游戏在NVIDIA  GTX 980上的设置为最高级别(译者注,这么翻译是根据我的

理解,Vulkan是一个支持低端机器运行Opengl的渲染接口,因此开到了最高模式),一些猜测来自于


Siggraph大会上Tiago Sousa(id首席程序员) 和Jean Geffroy.的展示。


Megetexture Update (巨型纹理更新)


   首先第一步是Mega-Texture更新,这是一种已经存在于RAGE中使用的ID Tech 

5中的技术,现在也在DOOM中使用。 如果要阐述这个算法的基本原理的话,这个

算法是在GPU内存上分配了几个巨大的纹理(16K x 8k的DOOM),每个纹理都是

128 x 128个 Tile(瓷砖拼图)拼贴的集合。


DOOM4图形研究16k x 8k storage with 128 x 128 pages


    所有这些Tile(瓷砖)都应该在好的mipmap级别代表理想的实际纹理集合,像

素着色器稍后将会渲染你现在正在看的游戏画面。


     当Pixel Shader(像素着色器)从“虚拟纹理”读取数据时,它只能从这些

128x128的某些物理Tile(瓷砖)中读取。

   当然这取决于玩家看的地方,玩家移动位置的时候,这个画面将会改变:新的

模型会出现在屏幕上,然后引用它所关联的虚拟纹理,新的Tile图块将会被

stream in(流式传入),旧的Tile流将被导出...
 
      所以在一帧的开始, DOOM4引擎使用vkCmdCopyBufferToImage命令来更新

了一些Tile瓷砖,将一些实际的纹理数据带入GPU内存。

对于idtech5 megetexture 技术的更详细的一个介绍,乃是出自,2012年的Siggraph,id程序员所写的论文

如果感兴趣, 05_ip_id_tech5_challenges.pdf 请去此处下载 
  
https://page35.ctfile.com/fs/14244535-201397199


H3D姚勇写的  RAGE来了-Megatexture信息更新.pdf 论文对于megetexture的一个叙述

下载地址 


对于Megetexture描述更加清晰的论文,由id程序员写的 Software-Virtual-Textures.pdf

如果感兴趣的话,请到此处下载 


shadow Map atlas (阴影贴图图集)


  对于每个灯投射一个阴影,生成一个独特的深度图,并将其保存到巨大的8k x   8k texture atlas (纹理图集)的一个Tile(瓷砖)中。然而,并不是每个帧都需要

计算出每一个深度图:DOOM4大量地重新使用前一帧的结果,并只重新生成需要更新的深度图。



DOOM4图形研究

灯是静态的,并且仅在静态对象上投射阴影时,只需简单地将其深度图保

8k * 8k的深度缓存器前一幁

DOOM4图形研究







8k*8k的深度缓冲器当前一幁


原样,而不是进行不必要的重新计算是有意义的。但是如果一些敌人在光线下移

动,则深度图必须再次生成。

  深度图尺寸可以根据与相机的光距离来变化,重新生成的深度图也不一定保持

在图集内的同一Tile内。

    DOOM4具有某些特定的优化,例如缓存深度图的静态部分,仅计算动态网格投
影并合成结果。

Depth Pr-Pass(深度预处理)

  现在渲染所有不透明的网格,仅将其深度信息输出到深度图中。首先是玩家的

武器,然后是静态几何数据,最后是动态几何数据。





速度图

但实际上深度并不是在深度预处理期间输出的唯一信息。
虽然动态对象(僵尸,电缆,玩家的武器)被渲染到深度图,但是它们每像素的

速度也被计算并写入另一个缓冲区以创建velocity map速度图。这通过在顶点着
色器中计算前一帧和当前帧之间的每个顶点的位置差来完成。


DOOM4图形研究Velocity 我们只需要2个channel(通道)来存储速度:红色是沿着水平轴的速度,沿着垂直轴是绿色的。

这个怪物迅速向玩家(绿色)移动,但是玩家手中的武器几乎没有移动(黑色)

黄色区域(红色和绿色等于1)?它实际上是缓冲区的原始默认颜色,没有动态网


格没有触及过:它是所有的“静态网格区域”。
  为什么DOOM跳过静态网格的速度计算?因为静态像素速度可以从其深度简单地

推断出来,而相机的状态自上一帧起就是新的state(状态),所以不需要在每个网

格的基础上进行计算。
the velocity速度图在稍后应用一些运动模糊将是有用的。

 occlusion Quieries( 遮挡查询)                                                                                                                     DOOM4图形研究
   
我们想发送尽可能少的几何渲染到GPU,所以实现这一点的最好方法是剔除玩家视 

野里面不能直接看到的所有网格。DOOM4中的大部分遮挡查询都是通过Umbra中间


件()完成的, 但引擎仍然会执行一些GPU遮挡查询来进一步削减视野外的数据


那么GPU遮挡查询背后是怎么实现的呢?
  首先是将游戏场景的几个网格组合成一个包含它们的虚拟框,然后请求GPU根据

当前的深度缓冲区渲染此框。如果没有一个光栅化像素通过深度测试,这意味着


盒子被完全遮挡,并且渲染时可以安全地省略该盒子中的所有世界对象。
那么事情是这些遮挡查询结果是不可用的,你不想阻止GPU管道阻挡一个查询。通


常,读取结果被推迟到以下帧,因此有必要使算法有点保守,以避免对象弹出。




Clustered-Forward-Rendering of Opeque Objects
(不透明对象的前向渲染)


  渲染所有不透明的几何和贴花。照明信息存储在HDR缓冲区中:

   深度测试函数被设置为EQUAL避免任何无用的overdraw(过绘制)计算,由于


之前的深度预处理(pre-pass),我们知道每个像素应具有哪个深度值。
当渲染网格时,贴图也直接应用,它们存储在纹理图集中。


  它已经看起来很好,但我们仍然缺少一些透明的材料,如玻璃,或颗粒,还没
有环境反射。

关于这个游戏的一趟渲染(pass):它使用一个聚集的前向渲染器,它受到Emil 

Person和Ola Olsson的作品的启发。

  历史上,前向渲染的一个缺点是它无法处理大量的灯光,在延迟渲染中更容易

处理。
 (译者注:前向渲染在单机fps中光源数量可以设定,同时一幁内的怪物数量已


知不是mmoprg玩家人数增多,像中国玩家的群战,几何数据未知。)

那么cluster(集群)渲染器是如何运行的呢?

 首先,您将您的视口划分成Tile(图块):DOOM创建一个16 x 8细分。一些渲染器

会停在这里,并计算每个Tile(图块)的灯光列表,这有助于减少照明计算量,但

仍然受到一些边缘情况的影响。



cluster Rendering(集群渲染)将从2D到3D进一步扩展,而不是停止在2D视口     DOOM4图形研究
 

细分,它实际上通过沿Z轴创建切片来执行整个相机平截头体的3D细分。


每个“块”被称为“群集”,您也可以将其称为“平截头体” 体素或“froxels
”。
右侧是一个简单的4 x 2视口细分的可视化,5个深度切片将平截头体分为40个群集。


在DOOM中,相机平截头体被分为3072个群集(16×8×24个细分),深度片沿着Z轴以对数方式定位。



使用集群渲染器,一个典型的渲染流程是:


首先,CPU计算影响每个集群内的照明的项目列表:灯,贴花和立方体... 
为此,所有这些项目都“体素化”,因此可以测试其影响区域与集群的交集。数


据作为索引列表存储在GPU缓冲区中,以便着色器可以访问它。每个群集最多可以

容纳256个灯,256个贴花和256个立方米。
然后当GPU呈现像素时:
从像素坐标和深度,确定其属于的集群
检索该特定集群的贴花/灯的列表。它涉及偏移间接和索引计算,如下所示。
代码循环遍历集群的所有贴花/灯光,计算并添加其贡献。
实际上,像素着色器可以在此通过期间检索灯光和贴花的列表:

还有探针列表(上图中未显示,),可以以完全相同的方式访问,但在此通行证中
未使用,所以我们稍后再回来。
  在CPU上预先生成每个簇的项目列表的开销是非常值得考虑的,它可以显着降低

GPU上的渲染计算复杂度。

 集群向前渲染最近越来越受到关注:它具有处理比基本转发更多的亮度的好处,

而比延迟更快,必须从多个G-Buffers写入/读取。

但有一些我还没有提到的:我们刚刚检查的这个pass(通道)不仅仅是一个写给
照明缓冲区的前进的一个; 而执行2次也使用MRT产生了2个G-Buffers 


   Normal Map  
                                                                                                                           
DOOM4图形研究























Specular Map

DOOM4图形研究






















法线贴图以R16G16浮点格式存储。镜面图在R8G8B8A8中,Alpha通道包含平滑因子



所以DOOM实际上巧妙地混合了前进和推迟与混合方法。当执行附加效果(如反射

)时,这些额外的G-Buffers将派上用场。
  最后一件事我省略了:同时也产生了一个160 x 120的反馈缓冲区,用于大型纹
理系统。它包含告诉流式传输系统哪些纹理应该流式传输mipmap级别的信息。
大型纹理引擎以反应的方式工作:在渲染传递报告后,某些纹理缺少引擎加载它们。


GPU Particles(GPU 粒子)

compute shader (计算着色器)被分配到更新粒子仿真:位置,速度和寿命。
它读取粒子当前状态以及正常和深度缓冲区(用于碰撞检测),起到模拟步骤的
作用,并将新状态存储到缓冲区中。

     Screen Space Ambient Occlusion(屏幕空间环境遮挡)

SSAO Map          

DOOM4图形研究
            

        在此步骤中,现在生成SSAO地图。


       其目的是使狭窄的接缝,褶皱变暗。
            它也用于应用specular occlusion镜面遮挡 以避免出现在被遮挡的网格上的明亮


照明上出现伪影。


  在从深度缓冲区,正常和镜面地图读取的像素着色器中,以原始分辨率的一半


计算。
获得的第一个结果是noise(嘈杂的)。
图像(左边)




Screen Space Reflections(屏幕空间反射)
一个像素着色器现在用于生成SSR映射。它仅使用存在于屏幕上的信息的光线追踪

反射,使得光线在视口的每个像素上反弹,读取由它们击中的像素的颜色。

Depth
DOOM4图形研究
Normal
DOOM4图形研究
Specular
DOOM4图形研究
Previous Frame

DOOM4图形研究


着色器的输入是深度图(用于计算像素世界空间位置),法线贴图(知道如何使
光线反弹),specular镜面图(知道反射量)和前一帧渲染(在pre-tonemapping

阶段,但后透明度,有一些颜色信息)。先前的帧摄像机配置也提供给像素着色

器,因此可以跟踪片段位置的变化。

 SSR是一个不错的,不太贵的技术,可以在现场进行实时动态反射,以保持不变

的成本,真正有助于沉浸和现实主义的感觉。
  但由于它纯粹在屏幕空间中工作,缺少“全局”信息,因此它自带的工件。所

以你可能会在一个场景中看到很好的反射,但是当你开始向下看时,反射的程度

会减少,直到看到你的脚就完全没有反思。我发现DOOM中的SSR很好地整合在一起

,它们提高了视觉质量,但是除非你真的专注于这些,否则你不会注意到它们消失。

Static Cubemap Reflections(静态立体图反射)

之前所有的动态反射趟数目(及其限制)现在都来自使用IBL的静态反射。
该技术基于预先生成的128 x 128立方米表示地图不同位置处的环境照明信息,也


称为“环境探测”。正如我们以前在截锥体聚类中所看到的光和贴花一样,探针


也按照与每个聚类相同的方式进行索引。
级别的所有立方体都存储在一个数组中,其中有几十个,但这里是这个场景的5个


主要贡献者(这个房间内的立方体):


/**************/




一个像素着色器从深度,正常的镜面缓冲区中读取立方体影响像素的群集结构(


立方图越靠近其影响越强)并生成静态反射图:


DOOM4图形研究

Blending Maps Together(地图所有映射混合)


在这个步骤中,计算着色器组合了之前生成的所有映射。
它读取深度和镜面地图,并将前进的照明与:


SSAO信息
当SSR可用于有问题的像素时
当SSR信息丢失时,静态反射映射数据被用作Fallback(回退)
还计算了一些雾效应

DOOM4图形研究





Particle lighting(粒子照明)


我们在这个场景中有一些烟雾粒子,照明实际上是根据精灵计算的。
每个精灵的渲染就像是在世界空间中:从它的位置,一些光列表和它们各自的阴


影贴图被检索,并且quad(四边形)上的照明被计算出来。然后将结果存储到4k


地图集的瓦片中,基于距离相机的粒子距离,瓦片可以具有不同的分辨率,质量


设置...图集具有相同分辨率的精灵的专用区域,这里是64 x64个精灵:


DOOM4图形研究



而这只是以这种低分辨率存储的照明信息。之后,当实际绘制一个粒子时,使用

全分辨率纹理,并将照明四面体放大并与之混合。
这是DOOM将粒子照明计算与游戏的实际主渲染分离的位置:无论您在播放的分辨

率(720p,1080p,4k ...),粒子照明总是计算并存储在这些微小的固定大小的
图块中。


Downscale and blur(低档和模糊,downscale我不知道该怎么翻译)

 场景被缩放了几次,下降到40像素。使用分离的垂直和水平通过,最小的缩小水平模糊。
       

DOOM4图形研究

为什么这个模糊如此早?这样的过程通常在后期处理过程中完成,以从明亮的地方产生绽放效应。

但是,在渲染玻璃折射时,所有这些不同的模糊级别将在下一趟中派上用场。
透明对象
所有透明物体(glass(我翻译成眼睛,因为doom4有头盔嘛),颗粒)都呈现在场景的顶部:


DOOM4图形研究

glass(此处翻译为玻璃)在DOOM中呈现非常好的特别是磨砂或肮脏的玻璃:贴花仅
用于影响玻璃的某些部分,使其折射或多或少模糊。

  像素着色器计算折射“模糊度”因子,并从模糊链中选择最接近该模糊因子的2
个图。它从这两个地图中读取,然后在2个值之间线性插值,以逼近折射应具有的
最终模糊颜色。这是由于这个过程,眼镜可以在基于像素的基础上以不同的模糊

水平产生良好的折射。

Distortion Map 失真地图                                                                                                    
  
非常热的地方可以在图像中产生热变形。在这里,戈尔巢地图稍微扭曲了形象。


对深度缓冲区进行失真,以创建低分辨率的失真图。
红色和绿色通道表示水平和垂直轴的失真量。蓝色通道包含要应用的模糊量。


实际效果稍后应用于使用失真图的后期处理来知道应该移动哪些像素。
虽然在这个场景中,特别是只有一个微妙的失真并不明显。








                                                                    用户界面

                                                         UI
 
DOOM4图形研究                                                   UI被渲染到以LDR格式存储的预乘法alpha模式中的不同渲染目标。
 将所有UI都放入单独的缓冲区,而不是直接绘制在最终的框架之上,这样的优点 是游戏可以一次性在所有UI小部件上应用一些过滤器/后处理,如色差或视觉失真。

在单程中。

渲染不会特别使用任何批处理技术,它会逐个绘制UI项目,大约有120个绘图调用。
在后面的过程中,UI缓冲区被混合在游戏图像之上,以产生最终结果。

Temporal Anti-Aliasing and Motion-Blur

(时间抗锯齿和运动模糊)

使用速度图和先前帧的渲染结果应用TAA和运动模糊。
片段可以被重新投影,因此像素着色器知道当前正在处理的像素位于前一帧中。渲染实际上每隔一帧将网格投影稍微移动一半像素:这有助于删除子像素的别名
伪像。



DOOM4图形研究


结果是非常好的:不仅网格边缘变得光滑,而且镜像混叠(其中一个亮像素将单
独弹出一帧)也被照顾。通过像FXAA这样的后期处理方法,质量远远好于可以实
现的质量。

Scene Luminance(场景亮度)

该步骤计算场景的平均luminace(亮度),这是晚些时候提供给tonemapper的参

数之一。


  HDR照明缓冲区在一个循环中被缩减到其分辨率的一半,直到它变为2×2纹理,

每次迭代计算像素颜色值作为其较高分辨率图中其4个父像素的亮度的平均值。
应用亮通滤镜来调暗场景最黑暗的区域。


  然后,亮通滤波器的结果在一个循环中被缩小,并且在我们之前看到的类似过程
   中模糊。
         层被模糊,高斯模糊分为垂直和水平遍历,其中像素着色器计算沿着一个方向的

DOOM4图形研究

  加权平均值。    然后将模糊的层组合起来,以创建在原始分辨率的1/4的HDR纹理的绽放。

Final Post-Processing(最终后期处理)

所有这一步都在一个像素着色器中执行:

读取失真图数据应用热失真
在HDR照明缓冲区的顶部添加了绽放纹理
执行如渐晕,污垢/镜片闪光的效果
通过对2×2亮度图的中心进行采样并使用附加的曝光参数来获取平均亮度,应用


调色板和颜色分级。
Tonemapping:之前
之后
以前下一个1
2
/******************/
tonemapping采用HDR照明缓冲器,其颜色在广泛的亮度范围内变化,并将其转换
为每个组件(LDR)的8位,因此可以将框架显示在显示器上。
  使用基于方程式的A filmic tonemapping operator(电影节拍操作员)
 (x(Ax+BC)+DE) / (x(Ax+B)+DF) - (E/F),它是“ 神秘海域2”色谱图,也出现
在GTA 5(侠盗猎车手5)中。
请注意,场景的所有普通红色都来自于颜色校正。


UI and Film Grain (界面和胶片颗粒)
最后,UI被混合在游戏框架的顶部,同时film-grain(胶片颗粒)被应用。

DOOM4图形研究


唷!我们完成了一幁的流程,现在可以将其发送到屏幕的监视器进行显示,这是
相当多的计算,但所有这些都发生在不到16ms。
 
 DOOM通过巧妙地重新使用以前的帧中计算出的旧数据,从而高性能地产生高质量
的视觉效果。总共有1331个draw call(绘制批次),132个纹理和50个渲染目标被使用。

Bonus Notes (额外备注)
Close-Up on Glass(玻璃上的特写镜头)
玻璃渲染是非常好的,它是通过我们以前看到的相对简单的步骤实现的:

准备几层不透明网格渲染的模糊
在Foward(前向模式)下使用贴花/照明/probe(探针)反射,在前面的方向绘制半透
明物品,使用前面处理过各种玻璃折射的模糊值,因此每个像素可以具有自身的
折射值。

DOOM4图形研究


景深
在在幁数的分析中没有真正显示任何景深,所以让我们考虑在应用DoF之前和之后
的以下场景:


DOOM4图形研究

  并不是所有的游戏都能正确执行DoF:传统的方法通常是使用高斯模糊,并根据

像素的深度在一次通过中进行所有的模糊。这种方法简单而廉价,但是有几个问题:

而高斯模糊对于boken(绽放)来说是不错的,创造a bright pixel spread(散景)
是不正确的:你真的需要一个平坦的内核,使一个明亮的像素的光散开在一个圆

盘或六边形的形状...高斯不能创造漂亮的散景形状。
在单次像素着色器中执行DoF可能会导致出血伪像。

DOOM能正确地执行DoF,在我的经验之中doom4使用的方法能够产生最好的结果:

创建Far_field 远场和near-field (近场)图像:根据其深度和DoF参数完成像素
DOOM4图形研究


选择。


near-fiedl (近处视野)可以产生增强的模糊效果,它会越多流入像素后面越好。
远场也模糊,但没有从对焦/近场区域读取任何像素,因此避免了前景对象错误地
渗透到背景中的任何问题。

为了创建boken blur(散景模糊),DOOM以半分辨率工作,并使用64个纹理抽头执

行disk -blur(磁盘模糊),
每个样本都拥有相同的权重,因此亮度真正与高斯模糊不同。
磁盘直径可以根据像素的CoC值在每像素的基础上变化。


然后,它进一步扩展了16分针模糊的模糊,但这次它不计算加权平均值,它只是

累积样本值并保持邻居抽头的最高值,因此不仅会扩大第一个模糊它也修复了第
一次通过的小物体(采样间隙)。最后一部分是McIntosh的工作灵感。

  考虑到获得的最终磁盘模糊的宽半径,这种在多次通过中的迭代技术可以产生


非常好的大模糊,同时仍然保持很好的性能,每像素执行的实际纹理抽头的数量
仍然相当低。

  远处的图像和近处的图像最终通过Alpha(蒙道)混合在原始场景的顶部合成,
以创建最终的景深效果。这个通过在应用运动模糊之前执行。


更多阅读

如果您想更深入地了解idTech 6技术,幸运的是有很多演讲和公共材料可供选择

The devil is in the details: idTech 666: Tiago Sousa和Jean Geffroy的,对于id tech6游戏引擎的一个更加详细的描述,有很多的相关技术。
(Siggraph 2016)  如果感兴趣的话,请到此处下载  idTech 666             
(魔鬼隐藏在细节之中)

olick的论文,olick-current-and-next-generation-parallelism-in-games.pdf
叙述了体渲染再加上光线投射即使乃是下一代的趋势,如果你对这篇论文感兴趣的话

请到下面地址
下载地址


技术采访:数字铸造企业Doom
id软件技术采访 DSOGaming

QuakeCon 2016:Doom Uncapped - Part1和Part 2

Doom:VentureBeat的最终面试

图形学宝典CryEngine 3  Sousa_Graphics_Gems_CryENGINE3.pptx(Siggraph 2013),
许多后处理技术都用于idTech 6。下载地址

写在后面的话
(译者注:我并不完全的赞同作者的全部观点,id tech6画面的强大,乃是在场景管理,多核心的系统优化,在加上引擎各个部分的优化,id tech6继承了id tech5的megetexture,渲染乃是几何,光照,纹理,最强,其他的shader效应,未必就是全部,我相信随着玩家的硬件的发展,id tech6 体素渲染,支持的几何,纹理数据增多,画面绝对越来越强悍,画面极致乃是在未来的,我拭目以待)