AMD Radeon™ Raytracing Analyzer
AMD Radeon™ Raytracing Analyzer (RRA) 是一款工具,可让您检查光线追踪应用程序的性能并突出显示潜在的瓶颈。
使用 DirectX 或 Vulkan API 进行光线追踪,首先需要构建加速结构,然后通过遍历这些加速结构来追踪光线。到目前为止,Radeon Raytracing Analyzer (RRA) 只提供了检查加速结构的方法,但没有办法查看遍历这些加速结构的光线的遍历数据。RRA 1.3 新增了一个 Ray (光线) 选项卡,可以显示光线遍历统计数据,并能以 3D 方式检查每条投射的光线。

TLAS 和 BLAS 选项卡已允许切换到遍历渲染模式,以模拟加速结构的遍历成本,但这可能与捕获的应用程序实际产生的成本有显著差异。模拟视图从视口相机为每个像素投射一条光线,而应用程序可以为每个像素投射任意数量的光线,这些光线不需要源自相机,并且可以具有独特的光线标志、剔除掩码和 Tmin/Tmax。Ray (光线) 选项卡允许查看所有投射的光线及其参数。这些信息将以热图的形式显示在 Dispatches (分发) 选项卡中,并且可以通过 Inspector (检查器) 选项卡以 3D 方式查看每条光线。
我们将着眼于利用新的光线功能解决一些常见问题。

上图显示了捕获的采样光线追踪渲染引擎中的最终光线追踪图像。大多数使用光线追踪的游戏都会谨慎地投射光线,考虑到光线追踪是一个成本很高的过程,这样做是合理的。为了测试 RRA,我们开发了一个示例引擎,它完全使用光线追踪渲染场景,具有软阴影和反射,并为每个像素投射多条光线。
打开包含光线数据的跟踪的光线 (Ray) 面板时,会有一个热图图像,可视化该分发的遍历统计信息。它显示的具体统计数据由其上方的下拉菜单设置。左侧显示了每个分发坐标的列表,数字对应于热图。请注意,热图中的每个像素通常与渲染图像中的像素紧密对应,除非使用了 Upscaling(上采样)或非 1:1 映射(如 1D 分发)。如果使用了 1D 分发,只要存在非稀疏映射,它们就可以重新映射到任何给定维度。

该热图看起来让人联想到 TLAS 和 BLAS 面板中的遍历渲染模式,不同之处在于,此视图不像遍历渲染模式那样是模拟的,并且不允许通过移动或旋转相机来改变视角;它是捕获应用程序中投射的光线的实际记录数据。
从热图的视觉上看,山下面似乎有很高的遍历成本。点击“Traversal loop count”(遍历循环次数)列标题将按总遍历成本对分发坐标列表进行排序。点击成本最高的条目,通过指向选定坐标的黑色光标会显示,它是中心树的反射中的少数几个昂贵调用之一,但目前我们对山下的区域更感兴趣。

在热图中单击并拖动鼠标左键可以绘制一个框,以便仅筛选列表中的选定分发坐标。选择山基部周围的框并再次对表进行排序,显示该区域中最昂贵坐标位于所选区域的右上角。

现在已经确定了一个问题区域,是时候研究改进遍历成本的选项了。
光线检查器 (Ray inspector) 可以轻松查看给定分发坐标中哪些光线设置了 RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH 标志,因为它们(默认)显示为薰衣草色。右下角的图例显示了每种光线类型的颜色,可以通过设置进行更改。让我们检查先前在山下选择的分发坐标,看看是否可以为任何光线启用此标志。选中分发坐标后,切换到 Inspector (检查器) 选项卡(或者也可以双击列表或热图中的坐标)。

检查器显示,目前没有光线使用此标志,因为它们都显示为绿色,但大多数光线用于检查命中位置是否被太阳遮挡。这些光线不需要知道最近的命中,只需要知道是否有命中,因此使用 RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH 标记它们是有意义的。在应用程序中进行此更改后,我们看到阴影光线现在显示为薰衣草色。

光线分发 (Ray dispatches) 面板显示,此更改使每条光线的平均遍历循环次数从 28.24 降至 26.01。
提高光线追踪性能最简单有效的方法是投射更少的光线。通过切换到热图光线计数着色模式,可以发现,如果主要光线未丢失,则会投射 10 或 6 条光线。

让我们检查先前在山下选择的分发坐标,看看是否可以在任何地方使用更少的光线。选中分发坐标后,切换到 Inspector (检查器) 选项卡。

投射了 10 条光线,一条是从相机投射的主要光线,然后从命中点投射 4 条阴影光线,以及一条反射光线,该反射光线自身又有 4 条阴影光线在其最近的命中处投射。主要光线和反射光线都跟随着 4 条阴影光线,但在渲染图像中,反射非常微妙。那么或许可以减少反射的阴影光线数量,而不会明显降低图像质量。通过将示例应用程序更改为在反射光线后仅投射 2 条阴影光线,会得到以下图像。

并且通过光线检查器可以验证投射的光线数量确实有所减少。

投射的阴影光线方向是从一个倾向于场景方向光方向的分布中绘制出来的。查看从背离方向光的三角形投射的光线,揭示了另一个优化机会。

光线的虚线表示光线被三角形几何体遮挡。那么这条阴影光线直接投射到了房屋墙壁上,尽管很明显结果会是命中。可以通过在着色器中检查新光线方向与三角形法线之间的点积是否为负来完全避免这些阴影光线。在实现这些更改后,分发面板显示我们现在投射了 9,437,792 条光线,而不是之前的 10,875,244 条。

同时使用光栅化和光线追踪的游戏可以通过跳过主要光线,并将次级光线的起点放置在深度缓冲区上来进一步减少光线数量。
当 alpha 测试三角形是命中候选者时,任何命中着色器 (any-hit shaders) 会在遍历期间被调用。在如此热的代码路径中调用着色器可能会对性能产生不利影响,因此建议减少或消除任何命中着色器的使用。
在分发面板中,将下拉菜单更改为“Color heatmap by any hit invocation count”(按任何命中调用次数对热图着色)将显示调用了任何命中着色器的分发坐标。

在示例应用程序中,树叶是唯一的非不透明几何体,因此每次任何命中调用都是由光线与其中一个叶子三角形相交引起的。主要光线调用任何命中着色器很重要,因为它对最终图像(叶子的睡莲形状)有易于识别的效果,但反射光线和阴影光线可以跳过调用任何命中着色器,而不会显着降低图像质量。通过对除主要光线之外的所有光线传递 RAY_FLAG_FORCE_OPAQUE 标志,任何命中调用的次数会显着减少,如热图所示,总调用次数从 1,360,096 减少到 323,359。

渲染图像的质量没有受到显着影响。

请注意,即使命中组没有任何命中着色器,标记为非不透明的几何体仍然会对性能产生不利影响,因此请务必将每个几何体标记为不透明,除非它需要使用任何命中着色器。
光线功能不仅可以帮助发现性能瓶颈,还是一个有用的工具,可以了解光线追踪着色器中发生的情况,并调试以意外方式投射的光线。如果没有检查每条光线的能力,唯一的线索就是分发的输出。在示例应用程序中,引入着色器错误后,结果图像如下。

反射发生了什么?根据渲染图像,这并不明显。追踪并查看光线检查器会发现,反射光线投射到了地面上,并且角度出乎意料,但阴影光线似乎没问题。

从视觉上看,反射光线反弹的方向似乎与入射光线来自相反方向时的情况一致。检查着色器中 reflect 函数的入射光线参数会发现,它确实是负值。
实现此处提到的每项优化后,渲染时间仅使用了原始渲染时间的 66.3%*,从 5.458 毫秒降至 3.621 毫秒,同时保持渲染图像与原始图像相似。树木的阴影在第二张图像中更暗,因为阴影光线没有调用任何命中着色器,但这可以通过创建带有小三角形的简化树叶三角形网格,并仅使用实例掩码将此实例用于阴影光线来缓解。
*测试配置:AMD Ryzen 9 7950X 16 核处理器,64 GB RAM,Radeon RX 7900 XTX,1080p。