挑战:无绑定光线追踪

镜子,另一面镜子上的...镜子。在本次挑战中,我们邀请您在 Metal 3 中探索无绑定渲染并在镜面上反射光线。

由于 Metal 3 中引入无绑定增强功能,HybridRendering 示例 App 看起来比以前更好了。它使用 Argument Buffers 为其着色器提供所有场景资源,然后使用 Metal 光线追踪在金属表面上产生反射 (如下所示)。

但是,尽管这款 App 描绘出了完美的场景,但仍然存在局限性:它无法显示反射中的反射,就像镜面地板反射镜面球体一样。

平心而论:镜子反射镜子是很难的!光会在两个表面之间无限反射,造成一种无法通过计算解决的状况。光线追踪 App 可在场景中添加有限数量的光 (或光线)“反射”来增强真实感,从而解决这个问题。

在本次挑战中,我们邀请您添加一个 (或多个) 额外的光线反射,从而扩展该光线追踪代码并增强图像的真实感。

开始挑战

在进入此镜子学堂之前,建议先观看“利用 Metal 3 实现无绑定”。看完之后,下载“Rendering reflections in real time using ray tracing”示例代码,我们将用它来应对本次挑战。

利用 Metal 3 实现无绑定

了解如何利用 Metal 3 实现无绑定,让渲染技术 (如光线追踪) 发挥其强大功能。我们将向您介绍如何通过简化参数缓冲区、分配来自堆的加速架构,以及运用 Metal 验证层和调试器工具的改进,使您 App...

Watch now

Rendering reflections in real time using ray tracing

该 App 有一个专门的计算通道,可以计算来自薄的几何缓冲区 (G-Buffer,其中包含图像中每个像素的位置和法线) 的反射。

光线追踪着色器会读取此数据,并将其与相机的视向相结合来计算反射光线的方向。然后,它将使用 Metal 来追踪这些光线、找到交叉点并对反射进行着色。

raytracing::ray r;
r.origin = positions.read(tid).xyz;
r.direction = normalize(directions.read(tid).xyz);
r.min_distance = 0.1;
r.max_distance = FLT_MAX;

raytracing::intersector<raytracing::instancing, raytracing::triangle_data> inter;
inter.assume_geometry_type( raytracing::geometry_type::triangle );
auto intersection = inter.intersect( r, accelerationStructure, 0xFF );
if ( intersection.type == raytracing::intersection_type::triangle )
{
  // Calculate direct reflections
}

这会产生以下图像:

但存在一个问题!球体在地板上的反射中没有了消防车。您需要应对的挑战是,通过修改光线追踪着色器 rtReflection 来添加额外的光线追踪步骤,让失踪的消防车显示出来。

要完成这项挑战,您将:

  1. 使用反射的法线和相交位置来计算光线的下一次反射。
  2. 将材质着色逻辑提取到一个辅助函数中,以便对反射中的反射进行着色。
  3. 将所有反射的颜色相结合并写入 outImage

完成后,使用截屏工具 GPU 调试器或 QuickTime 截取解决方案图像,然后使用话题标签 #WWDC22Challenges 在 Twitter 上展示您的作品。如果您想讨论无绑定光线追踪以及其他图形与游戏主题,请加入团队,参加 WWDC22 本周剩余时间举办的活动。

Explore #WWDC22Challenges on social media

Read the WWDC22 Challenges Terms and Conditions