Quantcast
Channel: 英特尔开发人员专区文章
Viewing all articles
Browse latest Browse all 583

合并蒙蔽遮挡剔除分层缓冲区,实现更快速的渲染

$
0
0

摘要

动态场景中的高效遮挡剔除可加速渲染,这使其成为游戏和实时图形社区的重要主题。由 J. Hasselgren、M. Andersson 和 T. Akenine-Möller 发表的一篇论文 蒙蔽软件遮挡剔除提出了一种针对支持 SIMD 的 CPU 进行优化的新算法,该算法剔除了传统遮挡剔除算法剔除的 98% 的三角形。尽管这种算法非常高效且准确,适用于许多用例,但仍存在启发法未充分解决的一些问题。在本文中,我们将对 Andersson 等人的先前工作进行补充。通过将场景分割为可以更好地拟合几何图形的局部动态范围并可以同时计算的多个缓冲区,从而解决了许多这些问题。然后,我们增加算法的丢弃启发法,并将部分结果缓冲区合并到一个新的分层深度缓冲区中,在该缓冲区上应用可以可靠地执行准确、高效的遮挡查询。

简介

蒙蔽软件遮挡剔除由英特尔的 J. Hasselgren、M. Andersson 和 T. Akenine-Möller 在 2015 年发明。它专为在适合游戏和实时图形社区的动态场景中进行高效遮挡剔除而设计。Andersson、Hasselgren 和 Akenine-Möller 在 2016 年随后提出的蒙蔽软件遮挡剔除算法的优势在于,它剔除了传统遮挡剔除算法所剔除的 98% 的三角形,同时比以前的工作快得多。此外,它仍可以充分利用 单指令多数据 (SIMD)指令集,与基于图形处理单元 (GPU) 的解决方案不同,它不会在系统中引入任何延迟。这对于游戏引擎开发人员非常重要,因为它可以使 GPU 免于不必要地渲染不可见的几何图形,渲染其他更丰富的游戏视觉效果。

Representation for the Intel castle scene
图 1.左侧:英特尔城堡场景中原始蒙蔽遮挡层次深度表示的可视化,黑暗离得更远;保守合并错误用红色突出显示。中间:城堡场景的游戏内视图,包括网格的边界框。右侧:使用两个单独分层缓冲区的合并来显示城堡场景的蒙蔽遮挡分层深度表示,准确性大幅提升。

该算法的更新版本 [HAAM16] 受到四片段合并 [FBH∗10] 的启发,该算法精度较低但性能较高,也被添加到蒙蔽遮挡库中。如果传入数据由前到后大致排序,则此方法效果最佳,这也可通过减少深度缓冲区中的透支来提高效率。

Typical workflow for Masked Occlusion Culling
图 2.典型的蒙蔽遮挡剔除工作流程。

图 2 显示了将蒙蔽遮挡剔除集成到游戏引擎中的典型工作流程。这个工作流程反映了传统的图形管道,并且已经被开发人员以这种格式使用,包括 Booming Games*Conqueror's Blade*,效果不错。

Masked Occlusion Culling buffer
图 3.Conqueror's Blade*的典型蒙蔽遮挡剔除缓冲区

然而,一些游戏工作负载显示,蒙蔽遮挡剔除效果较差的一个领域是在渲染具有明显深度重叠的超大网格时,因为重叠使得无法进行精确排序。经证明,这个问题在更新的 [HAMM16] 算法中特别突出。具体而言,在为广阔的环境渲染混合的前景资产和地形补丁时,问题就会显现出来。单个地形修补程序覆盖的深度范围很广,无法按照最佳顺序相对于前景遮挡物进行排序。这些间断是创建蒙蔽软件遮挡 HiZ 缓冲区时固有的,因为在建造缓冲区时用于丢弃图层的当前启发法不具备关于未来几何图形的足够上下文来保留最重要的数据。如果没有传入几何图形的完整上下文,启发法在深度选择过程中必须采取保守的方法,这会增加以后可见的遮挡查询的数量。这又意味着 GPU 不得不渲染最终被 GPU 剔除的几何图形,并且决不会对整个场景做出贡献。

为了解决这个问题,我们 [作者 Leigh Davies 和 Filip Strugar] 添加了将多个蒙蔽遮挡层次深度缓冲区合并到蒙蔽软件遮挡库中的功能。这允许开发人员利用分组场景几何图形和计算每个子组部分结果缓冲区的策略。选择子组是因为它们更紧密的深度值动态范围和以及几何分类行为。前景对象的子组和另一个地形对象的子组是常见情形。此类子组的部分遮挡结果稍后会合并到单个分层深度缓冲区中。部分缓冲区的这种合并使用现有丢弃启发法扩展来组合图层。

先前工作

蒙蔽软件遮挡光栅化算法与任何标准的两级分级光栅器相似 [MM00]。光栅化管道的一般流程如图 4 所示:

Masked Occlusion Rasterization Pipeline
图 4.蒙蔽遮挡光栅化管道,用于英特尔® 高级矢量扩展指令集 2(英特尔® AVX2)

三角形设置和图块遍历代码都经过高度优化,可高效使用 SIMD,可并行处理的三角形和像素的数量也不相同,具体取决于使用的 SIMD 的类型。蒙蔽遮挡剔除算法不同于标准软件光栅器有两个例外,下面将对其进行介绍。首先,它能够使用三角形边缘高效地并行计算整个图块的覆盖单元,而不是一次处理扫描线。

triangle rasterized on an Intel A V X 2 capable processor
图 5.在支持英特尔® AVX2 的处理器上进行光栅化的示例三角形。我们遍历三角形边界框所叠加的所有 32 x 8 像素单元,并使用简单的位操作和移位计算 256 位覆盖单元。

由于英特尔 AVX2 支持 32 位精度的 8 宽 SIMD,因此我们使用 32 x 8 作为图块大小,如图 5 所示(英特尔® SIMD 流指令扩展 2(英特尔® SSE2/英特尔 SSE4.1/英特尔® 高级矢量扩展指令集 512(英特尔® AVX-512)的图块大小将不同)。这使得算法可以非常高效地并行计算 256 像素的覆盖范围。

第二个区别是分层深度缓存表示,它将深度和覆盖数据分开,不需要存储全分辨率深度缓存。蒙蔽软件遮挡光栅化算法使用成本较低的混编重新安排遮罩,以便每个 SIMD 通道映射到更合适的 8 x 4 图块。对于每个 8 x 4 单位,分层深度缓冲区会存储两个浮点深度值 Zmax0和 Zmax1,以及一个表示每个像素与哪个深度值相关联的 32 位遮罩。在图 6 中可以找到由两个使用蒙蔽遮挡算法的三角形填充的图块的示例。

Tile fully covered by a blue and yellow polygon
图 6.在本例中,8 x 4 像素图块首先被一个蓝色多边形完全覆盖,随后被一个黄色三角形部分覆盖。左侧:我们在屏幕空间中看到的 HiZ 表示,其中每个样本属于 Zmax0或 Zmax1。右侧:沿着深度轴 (z),我们看到黄色三角形比蓝色多边形更接近。所有黄色样品(左)与 Zmax1(工作层)相关联,而所有蓝色样品与 Zmax 0 (参考层)相关联。

单层深度缓冲区的限制

鉴于我们每个图块只存储两个深度值,我们需要一种在每次三角形被光栅化(部分覆盖图块)时保守地更新表示的方法。参见图 7 中的伪代码,我们首先将 Zmax0分配为参考图层,该参考图层代表在图块中可见的最远距离,并且 Zmax <1> 值作为部分由三角形数据覆盖的工作层。

确定三角形覆盖范围后,我们将工作层更新为 Zmax1 = max (Zmax1, Zmaxtri),其中 Zmaxtri是图块边界内三角形的最大深度,并合并遮罩。当组合遮罩已满时覆盖图块,我们可以覆盖参考图层并清除工作层。

function updateHiZBuffer(tile, tri)
// Discard working layer heuristic
dist1t = tile.zMax1 - tri.zMax
dist01 = tile.zMax0 - tile.zMax1
if (dist1t > dist01)
tile.zMax1 = 0
tile.mask = 0

图 7.更新图块伪代码。

除了上面的规则之外,我们还需要一个启发法来决定何时放弃工作层。如图 8 所示,如果数据没有以完美的前后顺序进行提交,这有助于防止缓冲区中现有数据的轮廓通过更接近相机的遮光板泄漏。如上面的 updateHiZBuffer() 函数所示,如果到三角形的距离大于工作层和参考层之间的距离,我们会丢弃工作层。

蒙蔽遮挡更新程序旨在保证 Zmax0≥ Zmax1,所以我们可以使用带符号的距离来进行更快速的测试,因为如果当前三角形距离较远,我们不希望丢弃工作层。基本原理是深度较大的不连续性表示正在渲染一个新对象,并且连续的三角形最终将覆盖整个图块。如果工作层没有被覆盖,算法仍然需要保守地表示深度缓冲区。

Hierarchical depth buffer
图 8.顶部:分层深度缓冲区的两个可视化。生成左侧图像时不使用启发法来丢弃图层。请注意,背景物体的轮廓通过遮光板泄漏,在浅灰色的前景物体上显示为较暗的灰色轮廓。右图使用我们的简单图层丢弃启发法,保留了传统深度缓冲区几乎所有的遮挡精度。底部:我们的丢弃启发法应用于图 2 中的样本图块。根据我们的启发法,黑色三角形会丢弃当前工作层,并覆盖 Z1最大值。基本原理是深度较大的不连续性表示正在渲染一个新对象,并且连续的三角形最终将覆盖整个图块。

参考图 9,由于用于丢弃工作层的启发法未被触发,因为参考层在工作层后面很远,所以剩余的轮廓边缘通过遮光板发生了泄漏。在问题情况下,参考图层包含清除值,导致深度值的动态范围很宽。工作层用来自工作层和新三角形的最保守值进行更新。尽管连续的三角形最终覆盖整个图块,并且工作层可能使用了来自传入三角形的更近的 Zmax 值。

Single hierarchical depth buffer
图 9.仅使用单个分层深度缓冲区,在排序良好的场景中轮廓渗出。

去除地形上的轮廓渗出

图 9 显示了高分辨率轮廓渗出的最终效果。当靠近观察者的物体在包含远处物体和清晰颜色的图块中进行渲染时,将出现最突出的轮廓渗出情况。这是由于需要在图块层中保留最保守的值,且没有以后还可以渲染哪些内容的上下文。一个潜在解决方案是,仅在添加了新网格的全部数据时才将数据合并到一个图块中,但这需要能够在分层深度缓冲区中存储更多图层。

解决轮廓渗出问题的另一种方法是将地形和前景对象渲染到自己的分层深度缓冲区中,然后单独渲染它们。这可大幅减少分层深度缓冲区中的间断。前景物体几乎没有渗出,因为粗糙的前后排序足以确保三角形按照最适合掩蔽遮挡丢弃算法的顺序呈现。由于单个网格内的三角形的内部排序,地形存在一些渗出问题,但是这些更加局部化。图 10 显示了分离的分层深度缓冲区。这只剩下合并地形网格和现有前景对象的问题,以生成可用于剔除的最终分层深度缓冲区。

Castle scene with terrain and foreground objects
图 10.城堡场景与地形和前景对象在单独的缓冲区中。

合并缓冲区

添加到掩蔽遮挡 API 的新合并功能就是这样的,用第二个分层深度缓冲区,将数据合并到第一个深度缓冲区中。合并算法在相同的 8 x 4 图块基础上运行,使用与用于光栅化的合并启发法相同的 SIMD 指令,从而允许并行处理多个子图块。合并代码已针对原始合并算法 [AHAM15] 和更新版本 [HAAM16] 实施。合并算法的流程如下所述:

1.使用参考 + 工作层计算图块的保守深度值。对于 HAAM16 来说很简单,因为这是参考层,对于 AHAM1 稍微复杂一些。

New Reference Layer = _mm256_max_ps(Valid Reference A[0], Valid Reference B[0]);

2.比较缓冲区 A 层与新参考层的运行情况。遮掩未通过深度测试的所有图块 -用深度测试的结果更新新参考图层

3.将缓冲区 B 的工作层视为传入三角形。将缓冲区 B 层的运行情况与新的参考层进行比较 遮掩未通过深度测试的所有图块。如果传入的三角形比新工作层更接近观察者,则使用距离启发法丢弃第 1 层。使用传入三角形覆盖更新新遮罩。

计算 zMin[1] 的新值这是四项成果之一:

zMin[1] = min(zMin[1], zTriv)
zMin[1] = zTriv
zMin[1] = FLT_MAX
未更改

取决于图层是更新、丢弃、完全覆盖还是未更新。如果图块完全覆盖,将 zMin[1] 传送回 zMin[0],并更新遮罩。

在实践中,我们发现对于像城堡这样的场景,我们只需要使用两层;只需稍作修改,代码就可以组合多个缓冲区。最终的合并缓冲区如图 11 所示。原始轮廓问题已经完全解决。

Final hierarchical depth buffer
图 11.从合并的前景和地形缓冲区创建的最终分层深度缓冲区的可视化表示。

缓冲区的合并不能解决单个缓冲区的渗出问题,例如地形方面的内部问题。但它确实可以确保它们在被另一组几何体中的数据覆盖时不会向前传播。在城堡中,它们被前景物体覆盖。

表 1 显示了不同分辨率下合并算法的性能;性能与分辨率成正比,而用于合并 HI-Z 数据的代码使用与其余 MOC 算法相同的一组 SIMD 指令。这里提供的数据是使用英特尔 AVX2 生成的,因此可并行处理 8 个子图块,但这可以通过英特尔 AVX-512 扩展到最多 16 个子图块。

表 1.相对于分辨率的合并成本;性能在英特尔® 酷睿™ i7-6950X 处理器上测量得出。

 地形光栅化时间 (ms)前景光栅化时间 (ms)总光栅化时间 (ms)合并时间 (ms)合并所用的时间百分比
640 x 4000.190.6520.8420.0080.9%
1280 x 8000.260.7721.0680.0272.5%
1920 x 10800.310.8341.1440.0514.4%

合并功能会跳过不需要合并的图块,因为只有一个缓冲区在图块中具有有效数据作为优化。尽管有固定的数据集遍历成本来检查这一点,但掩蔽遮挡层次深度缓冲区的低内存占用空间是合并性能的主要原因。在 1920 x 1080 分辨率下,屏幕由 64800 (8 x 4) 个子图块组成,每个子图块只需要 12 个字节的存储。合并函数只需读取 760 Kb,而传统的 32 位深度缓冲区则超过 8.1 MB。另外,通过使用英特尔 AVX2,我们可以并行处理八个子图块。表 1 中的时间表示单线程性能。合并线程化方面的实验表明,由于受到内存限制,所获得的优势不多。在每秒运行速度为 60 帧的 PC 图块上,一个 1080p 缓冲区可以并入单个内核上一帧的 0.5%。

使用缓冲区合并来并行化分层深度缓冲区创建

掩蔽遮挡库已经提供了一种用于并行创建分层深度缓冲区的方法。通过使用图块渲染系统(即传入网格发送到作业系统且并行渲染),几何变换阶段产生的三角形输出存储在代表屏幕空间图块的分箱列表中,然后由每个线程的作业系统进行处理,从而对一个屏幕空间图块的几何图形进行光栅化处理。分层深度缓冲区的合并提供了一种替代方法,适用于更粗的粒度,并且不需要将几何图形存储在临时结构中。典型设置如图 12 所示。任务系统最初调度两个遮光板渲染任务,并创建一个在两个渲染任务都完成时进行触发的合并任务。

Potential multithreading setup
图 12.用于蒙蔽遮挡剔除的潜在多线程设置。

合并任务完成后,渲染应用的实际遮挡查询可以根据需要在任意数量的线程上发布。理论上,前景遮挡物渲染任务可以进一步细分。如果它们之间的工作量非常不均匀,如果每个附加任务的成本是一个额外的合并任务,并且合并功能可以进一步修改以管理多个缓冲区(如果需要),这可能是有利的。以这种方式进行线程化的一个额外好处是可以移除所需内存并节省相关带宽,无需写出变换和光栅化过程之间的几何图形。总体而言,这种将场景分割成两个或多个蒙蔽遮挡剔除缓冲区并使用独立线程处理它们的方法支持功能性线程模式,这种模式适用于不支持英特尔拼贴算法所需的细粒度任务系统的引擎。

结论

我们对蒙蔽软件遮挡剔除的扩展为您提供了一种灵活的解决方案,可以在不影响原始蒙蔽遮挡算法性能的情况下,为无法充分预分类的场景提高深度缓冲区的最终精度。我们方法中的合并时间与分辨率呈线性关系,并且与场景中的几何复杂度无关。在测试案例中,我们的方法仅占剔除系统所需总时间的一小部分。最终优势在于,我们的部分结果分组可以实现新的线程级并行机会。这些改进可提供强大、快速且准确的基于 CPU 的几何图形剔除。整体而言,这些改进大大降低了游戏引擎采用蒙蔽软件遮挡剔除的门槛,可释放 GPU 渲染资源,从而提供更丰富的游戏体验。

参考

[AHAM15] M. Andersson、J. Hasselgren、T. Akenine-Möller:图形硬件的蒙蔽深度剔除。ACM 图形交易,34,6 (2015),188:1–188:9.2, 4, 5, 8

[FBH∗10] K. Fatahalian、S. Boulos、J. Hegarty、K. Akeley、W. R. Mark、H. Moreton、P. Hanrahan:使用四片段合并减少 GPU 上的阴影。ACM 图形交易,29,4 (2010),67:1–67:8.4

[HAAM16] M. Andersson、J. Hasselgren、T. Akenine-Möller:蒙蔽软件遮挡剔除

[MM00] J. Mccormack、R. Mcnamara:在图形硬件中使用半平面边缘函数进行图块多边形遍历 (2000),pp.15– 21.2


Viewing all articles
Browse latest Browse all 583

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>