大多数浏览器和
Developer App 均支持流媒体播放。
-
使用 Metal 光线追踪增强你的 App
通过 Metal 技术图形框架和着色语言的核心部分,即光线追踪,在 app 和游戏中实现逼真的 3D 场景。我们将探索实现光线追踪的最新改进,并带您了解生产渲染过程的升级。探索 Metal API 以帮助您创建更细致的场景、将原生支持的内容与动作相集成等等。
资源
- Accelerating ray tracing using Metal
- Applying realistic material and lighting effects to entities
- Managing groups of resources with argument buffers
- Metal
- Metal Shading Language Specification
- Rendering reflections in real time using ray tracing
相关视频
Tech Talks
WWDC23
WWDC22
WWDC21
-
下载
♪低音音乐播放♪ ♪ 胡安罗德里格斯奎利亚尔:你好 欢迎来到WWDC 我是胡安罗德里格斯奎利亚尔 是Apple的GPU编译器工程师 在本次会议中 我们会讨论 我们今年新增的全新功能 以增强我们的金属材质光线追踪API 但首先 让我们快速回顾一下 光线追踪 光线追踪app是基于追踪光线 与场景交互时的路径 光线追踪应用于音频 物理模拟、人工智能等领域 但其中一个主要的应用是逼真的渲染 在渲染app中 光线追踪用于模拟单个光线 这使我们能够模拟反射 柔和阴影和间接照明等效果 这只是光线追踪的一般定义 让我们来谈谈金属材质的方法 我们从计算内核开始 在我们的内核中 我们生成光线 这些光线被发射到场景中 然后 我们用交集和加速结构 在场景中的几何体上 测试这些光线的交集 每个交点 代表光线从表面反射 光的反射量和反射方向 决定了物体的外观 然后我们为每个交集计算颜色 并更新图像 这个过程被称为着色 它也可以产生额外的光线 这些光线也会被测试交集 我们重复这个过程很多次 因为我们想要模拟光线 在场景周围的反弹 今年 我们的新功能主要集中在 三个方面 首先 我将讨论我们如何为渲染管线 添加光线追踪支持 这允许我们将光线追踪与渲染混合 然后我将向你介绍 专注于可用性和可移植性的新功能 这些功能将简化金属材质 光线追踪API的使用 最后 我将介绍我们今年添加的 产品渲染功能 这些功能将帮助你创建更逼真的内容 让我们从渲染管线的光线追踪开始 让我们考虑 一个渲染的基本情况 它只有一个渲染通道 随着我们对渲染管道的 光线追踪的新支持 这使得在渲染中 添加光线追踪变得非常容易 但是 如果没有此支持 要使用去年的金属材质光线追踪API 向此渲染添加光线追踪 我们需要添加计算通道 让我们先在渲染后添加它 来增强渲染后的图像 添加这个额外的计算通道 代表将更多的输出写入内存 以便用于光线追踪的计算通道 现在 如果我们想在渲染过程中 使用光线追踪来计算一个值 例如每个像素的阴影呢? 这代表我们需要分割渲染 并引入一个计算通道 仔细想想这代表什么 我们需要将像素位置和法线 作为光线追踪的输入写入内存 然后读取交集结果 可能需要多次读取 但是有了从渲染阶段 对光线追踪的新支持 我们永远不需要离开渲染通道 我们只需要将输出写入内存 让我们看看我们如何使用 我们的新API 为光线追踪准备渲染管道 类似于计算管道 首先构建加速结构 并定义自定义交集函数 为了支持自定义交集 我们需要一个交集函数表 我们需要用交集函数填充它 这部分与去年的API相比有些不同 我们来看看怎么做 让我们考虑一些简单的交集函数 我这里有一些函数 可以让我们 分析交集对象 例如球体 圆锥体或环面 当我们创建管道时 我们将这些函数添加为 我们可以调用的链接函数 在本例中 我们将它们添加到 管道的片段阶段 要使用这些函数 我们需要从管道状态和阶段 创建一个交集函数表 一旦我们有了表 我们就可以从管道状态 和阶段创建函数句柄 并填充表 为片段阶段指定函数重用 我们去年引入的 linksFunctions对象 在呈现管到描述符上 每个阶段都有自己的一组 linkedFunctions 创建交集函数表 与为计算管道完成时非常相似 唯一的变化是添加了stage参数 为了填充表 我们创建了函数句柄 同样 句柄是特定于阶段的 因此我们需要在请求句柄时指定阶段 一旦我们有了函数句柄 我们就把它插入函数表中 这就是你在渲染管道中准备函数表 所需要做的一切 现在我们只需要利用现有的一切 来实现交集 实际使用很简单 accelerationStructure 和交集函数表 都绑定到渲染编码器上的缓冲区索引 然后着色器可以使用这些资源 来交集光线 就像在计算内核中一样 更多关于如何准备 光线追踪管道的细节 可以在去年的演讲中找到 在该演讲中 你会学到 如何构建加速结构 创建函数表 以及在着色语言中使用intersector 通过渲染管线的光线追踪支持 我们为更多机会打开了大门 例如在单个渲染通道中添加光线追踪 在混合渲染中混合光线追踪 和光栅化 以及利用Apple Silicon上的 tile功能等优化 事实上 我们很快就会 把光线追踪添加到我们在 WWDC 2019的《金属中的现代渲染》 演讲期间示范的示范app中 通过渲染管道的光线追踪 我们可以更新代码 使用平铺函数 将所有内容保留在平铺内存中 要了解更多细节 请参阅今年的演讲 《探索使用金属光线追踪的混合渲染》 接下来 我想介绍 我们今年添加的新功能 以改进金属材质光线追踪API的 可用性和可移植性 这些功能不仅提供了 更简单的金属材质光线追踪使用 而且还提供了其他 光线追踪API的可移植性 这些新功能之一是交集查询 通过交集查询 我们让你对交集过程 有更多的控制 交集查询的目标是简单的用例 在这些用例中 交集可能会产生开销 这是一种穿越加速结构的新方法 让你可以选择执行 内联自定义交集测试 让我们来看看我们目前如何使用 去年的intersector处理自定义交集 回到去年使用金属材质 进行光线追踪的 alpha测试示范 我们示范了如何使用alpha测试 为场景添加许多几何细节 就像你在这里看到的链条和树叶 我们还了解到 通过使用三角形交集函数 自定义一个交集来实现 alpha测试是多么容易 当光线穿过加速结构时 此三角形交集函数内部的逻辑 负责接受或拒绝交集 在这种情况下 测试逻辑将拒绝第一个交点 但它会接受第二个交点 因为已与不透明表面交集 让我们看看如何使用交集函数 当使用Intersector时 当你调用intersect()时 我们开始遍历加速结构 以找到一个交集 并填充我们的intersection_result 在交集内 每次找到潜在的交集时 都会调用交集函数 然后根据交集函数逻辑 接受或拒绝交集 这是一个很好的 使用intersector的编程模型 因为它既高效又方便 但它确实需要创建一个新的交集函数 并将其连结到管道 在某些情况下 交集函数内部的逻辑 只有几行代码 就像alpha测试逻辑的情况一样 这个交集函数 包含了进行alpha测试的逻辑 使用交集查询 我们可以将这个逻辑内联 而不需要这个交集函数 以下是我的解释 使用交集查询 当你开始交集过程时 你的光线会遍历加速结构 查询对象包含遍历的状态 和结果 每次光线与自定义图元 或非透明三角形交集时 控制权都会返回给着色器 以便你评估交集候选对象 如果当前的候选选项 通过了你的自定义交集逻辑 则提交它以更新 当前提交的交集 然后继续交集过程 另一方面 如果候选的自定义交集逻辑失败 你可以直接忽略它并继续 让我向你展示使用交集查询 进行alpha测试的代码 首先 开始遍历 请注意 我们使用next循环 来评估所有候选交集 其次 你从检查候选类型 开始评估每个候选选项 对于alpha测试示范 你对三角形类型的交集感兴趣 在检查类型后 你将需要查询 有关候选的一些交集信息 我们对现在内联的alpha测试逻辑中 所需的信息执行三个查询 最后 如果候选交集 通过了alpha测试 你将提交它 使其成为 当前提交的交集 到目前为止 你已经遍历了整个加速结构 评估候选交集 并提交 通过alpha测试逻辑的交集 现在 你需要查询已提交的交集信息 以进行着色 首先 你将查询提交的类型 如果没有一个候选交集 满足你的条件成为提交的交集 则提交类型将为none 这代表当前光线错过了 另一方面 如果有一个提交的交集 你会想要查询 适用于该交集类型的 交集的信息 然后将其用于着色 这就是使用交集查询 执行alpha测试所需的全部代码 随着交集查询 和交集渲染管道的引入 我们为你提供了更多机会 开始将金属材质光线追踪 引入你的app 以下是在选择交集对象 和交集查询之间 需要考虑的一些事项 首先考虑你是否有现有代码 例如在计算中使用交集 以及你移植该代码的计划 如果你有来自其他API的 现有查询代码 交集查询可以帮助移植该代码 接下来 你将面临 处理自定义交集的复杂性 交集需要交集函数和表格 使用交集查询自己处理 自定义交集可能更容易 最后一个问题是性能 在更简单的情况下 交集查询可以在构建用于 光线追踪的管道时避免开销 但自定义交集处理 需要在遍历期间返回到你的代码 这可能会影响性能 具体取决于用例 此外 使用多个查询对象 将需要更多内存 另一方面 跨部门可以通过封装所有交集工作 来支持那些更复杂的情况 如果有机会 我们建议你 比较两种解决方案的性能 这就是交集查询的全部内容 现在让我们继续介绍其他一些新功能 接下来我们要讨论的两个功能 是用户实例ID和实例转换 这些功能将帮助你向加速结构 添加更多信息 并访问更多已有数据 这就是为什么我们认为 这些是非常有用的功能 如果我们回顾去年示范中的 示范代码 我们有多个内核盒实例 在此之下 我们有一个实例加速结构 其中包含一组节点 这些节点分支直到你到达实例 查看其中两个实例 它们处于实例加速结构的 最低级别 目前 当你与这些实例之一交集时 你只能从交集结果中 获取系统的实例ID 有了这个 你可以维护自己的数据表 但我们可以在加速结构中 公开一些数据来帮助你 我们先说一下用户自定义的实例ID 使用此功能 你可以为每个实例指定一个 自定义的32位值 然后将该值 作为交集结果的一部分 这对于你索引到 你自己的数据结构非常有用 但它也可用于编码自定义数据 例如 这里我们使用用户ID 为每个实例编码自定义颜色 你可以将其用于更简单的反射 而无需查找任何其他材料信息 这只是一个例子 但机会是无穷的 我可以看到你希望如何对 每个实例的材质ID 或每个实例的标志等内容进行编码 我们创建了用于指定 这些ID的实例描述符类型的 扩展功能版本 确保在实例加速结构描述符上 指定你使用的描述符类型 在着色语言中 当前用户实例ID的值 可用作具有实例化 标记的交集函数的输入 要获取交集后的值 在使用交集对象时 可以从交集结果中 获得用户定义的实例ID 并且当使用交集查询对象时 有一个相应的查询 来访问候选和提交的 交集的用户定义的实例ID 就像用户实例ID一样 我们添加了 对访问你的实例转换矩阵的支持 此数据已在实例描述符中指定 并存储在加速结构中 今年 我们从着色语言中 公开了这些矩阵 当你应用instancing 和world_space_data标签时 你可以访问交集函数中的实例变换 同样地 当使用带有instancing 和world_space_data标签的交集时 在交集结果中提供了实例变换 当使用带有实例化标签的交集查询时 对于候选和提交的交集 都有相应的 访问实例转换的查询 总而言之 今年我们通过 引入三个新功能来提高 金属材质光线追踪API的 可用性和可移植性 交集查询作为交集的替代方案 提供对交集过程的更多控制 随着用户实例ID 和实例转换功能的引入 我们为你提供了从加速结构 访问数据的能力 而不必在你的代码中 处理一些外部映射 此外 这三个功能 提供了其他光线追踪API的可移植性 使跨平台开发变得更加容易 到目前为止 我们已经讨论了 我们对渲染管道中光线追踪的 新支持以及我们今年添加的 不同可用性 和可移植性功能 现在 让我向你展示我们正在引入 哪些功能来增强产品渲染 自从去年引入 金属材质光线追踪API以来 人们一直在使用它来渲染 一些令人惊叹的高质量内容 今年 我们添加了两个新功能 以便呈现更好的内容 让我们从扩展功能限制开始 自从我们发布 金属材质光线追踪API以来 一些用户开始遇到我们加速结构的 内部限制 尤其是在生产规模的用例中 因此 我们正在添加 对扩展功能限制模式的支持 以支持更大的场景 去年 我们选择了这些限制 来平衡加速结构的尺寸 以支持典型场景大小的性能 打开此功能 可能会影响性能 因此你需要确定 哪种模式最适合你的app 扩展功能限制模式增加了 对基元、几何图形、实例数量 以及用于过滤实例的 掩码大小的限制 要开启它 你首先在构建加速结构时 指定扩展功能限制模式 然后在着色语言中 在交集对象上 指定extended_limits标签 这就是你开启扩展功能限制 所需要做的一切! 接下来 让我们谈谈运动 在计算机图形学中 我们通常假设相机曝光是瞬时的 然而 在现实生活中 相机曝光持续时间是非零的 如果一个物体在这段时间内 相对于相机移动 它会在图像中显得模糊 在这个极端的例子中 中间的人在整个曝光过程中 一直保持静止 而其他人一直在移动 导致他们变得模糊 这种效果可以使计算机 生成的图像看起来更逼真 在此示范中 球体在多个帧之间进行了动画处理 但每一帧仍然是瞬时曝光 从而导致动画断断续续 使用运动API 我们可以模拟持续非零时间的 相机曝光 这会产生更流畅 更逼真的动画 如果我们冻结视频 你可以看到球体的边界在运动方向上 变得模糊 就像真正的相机一样 游戏等实时app 通常在屏幕空间中近似这种效果 但是光线追踪使我们能够模拟 物理上准确的运动模糊 甚至可以扩展功能到阴影和反射等 间接效果 让我们来看看 运动模糊版本是如何渲染的 运动模糊是光线追踪的直接扩展功能 大多数光线追踪app已经随机采样 物理维度 例如间接照明的 入射光方向 要添加运动模糊 我们也可以为每条光线 选择一个随机时间 金属材质将与场景交集 以匹配与每条射线 相关的时间点 例如 这条光线会看到这样的场景 另一条光线会看到这样的场景 随着我们积累越来越多的样本 我们将开始收敛于运动模糊的图像 实际上 你今天已经可以使用 自定义交集函数来实现这一点 你可以在整个曝光过程中 计算每个基元的边界框 然后使用这些边界框 构建加速结构 然而 这将是低效的 边界框可能非常大 以至于某些光线需要检查 与它们实际上永远不会交集的 图元是否交集 相反 我们可以使用金属材质 对运动模糊的内置支持 该支持旨在有效处理此类情况 我们需要做的第一件事是将随机时间 与金属材质着色语言代码中的 每条光线相关联 我们首先在曝光间隔内 生成一个随机时间 然后将其传递给交集点 接下来我们需要做的 是将动画几何体提供给金属材质 我们使用一种称为关键帧动画的 常用动画方法来做到这一点 通过在称为关键帧的关键时间点 对球进行建模来创建动画 这些关键帧均匀分布在 动画的开始和结束之间 当光线穿过加速结构时 它们可以根据它们的时间值 从任何关键帧中获取数据 例如 光线A会看到 在关键帧11中建模的场景 因为它的时间恰好与关键帧11匹配 相比之下 光线B的时间 在关键帧3和关键帧4之间 因此 两个关键帧的几何图形 为光线B进行插值 在实例和原始级别 都支持运动 实例动画可用于 刚性变换整个对象 这比原始动画便宜 但不允许对象变形 另一方面 原始动画更昂贵 但可用于诸如蒙皮角色动画 之类的东西 请注意 实例动画和原始动画 均基于关键帧动画 让我们先来谈谈实例运动 在实例加速结构中 每个实例都与一个变换矩阵相关联 这个矩阵描述了 在场景中放置几何体的位置 在这个例子中 我们有两个基本的加速结构 一个用于球体 另一个用于静态几何 每个原始加速结构都有一个实例 为了动画球体 我们将提供两个变换矩阵 代表动画的起点和终点 金属材质将根据每条射线的时间参数 对这两个矩阵进行插值 请记住 这是一个使用两个关键帧的 特定示范 但金属材质支持任意数量的关键帧 我们使用加速结构 描述符提供这些矩阵 标准的金属材质实例描述符 只有一个转换矩阵的空间 因此 我们将使用 新的运动实例描述符 使用此描述符 变换矩阵存储在单独的缓冲区中 然后 实例描述符包含一个表示 变换缓冲区中变换矩阵范围的 起始索引和计数 每个矩阵代表一个关键帧 让我们看看如何使用新的运动实例 描述符类型设置实例描述符 我们从创建常用的 实例加速结构描述符开始 然后我们指定我们使用 新的运动实例描述符类型 然后 我们指定 包含运动实例描述符的 instanceDescriptorBuffer 最后 我们需要绑定 包含每个关键帧的 顶点缓冲区的transformsBuffer 其余属性与任何其他 实例加速结构相同 我们也可以像任何其他 加速结构一样构建它 我们只需要在着色语言中 进行一项更改 即指定instance_motion标签 这告诉交集期望 具有实例运动的加速结构 这就是我们设置实例运动 所需要做的一切 接下来 让我们谈谈原始运动 使用原始运动 每个图元可以单独移动 这代表它可以用于 诸如蒙皮角色动画之类的事情 请记住 我们需要为每个关键帧 提供一个单独的3D模型 然后金属材质将在它们之间进行插值 我们需要为每个关键帧提供顶点数据 让我们看看如何设置它 我们首先将每个关键帧的顶点缓冲区 收集到一个数组中 MTLMotionKeyframeData对象 允许你指定缓冲区和偏移量 我们将使用它来为每个关键帧指定 顶点缓冲区 接下来 我们将创建一个 运动三角形几何描述符 这就像创建任何其他几何描述符一样 只是我们使用了稍微不同的类型 而不是提供单个顶点缓冲区 我们将提供我们的顶点缓冲区数组 最后 我们将创建通常的 原始加速结构描述符 接下来 我们提供我们的 geometryDescriptor 然后我们将指定关键帧的数量 与实例运动类似 我们需要对着色语言 进行一些小的更改 以指定primitive_motion标签 这就是我们设置原始运动 所需要做的一切! 请记住 对于更加动态的场景 你实际上可以同时使用 这两种类型的动画 接下来 让我们来看看 这一切的行动吧! 这是由我们的高级内容团队创建的 路径追踪渲染 该视频是在配备 AMDRadeonProVegaIIGPU的 MacPro上渲染的 忍者角色使用蒙皮骨骼动画技术 进行动画制作 该技术允许每个基元单独移动 通过组合使用原始运动API 采集的256个随机定时样本 来渲染每一帧 我们可以放慢速度 以更清楚地看到差异 左边的版本没有运动模糊 而右边的版本有 我们可以进一步增加曝光时间 来模拟长时间曝光 运动模糊可以在真实感上 产生很大的不同 现在可以很容易地使用 新的运动API添加 这就是运动 感谢收看这场演讲 我们在金属材质光线追踪API中 投入了大量工作 以提供增强app所需的工具 我们迫不及待地想看到 你用它创作的精彩内容 谢谢你 祝WWDC愉快! ♪
-
-
4:48 - Specify intersection functions on render pipeline state
// Create and attach MTLLinkedFunctions object NSArray <id <MTLFunction>> *functions = @[ sphere, cone, torus ]; MTLLinkedFunctions *linkedFunctions = [MTLLinkedFunctions linkedFunctions]; linkedFunctions.functions = functions; pipelineDescriptor.fragmentLinkedFunctions = linkedFunctions; // Create pipeline id<MTLRenderPipelineState> rayPipeline; rayPipeline = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
-
5:02 - Create intersection function table
// Fill out intersection function table descriptor MTLIntersectionFunctionTableDescriptor *tableDescriptor = [MTLIntersectionFunctionTableDescriptor intersectionFunctionTableDescriptor]; tableDescriptor.functionCount = functions.count; // Create intersection function table id<MTLIntersectionFunctionTable> table; table = [rayPipeline newIntersectionFunctionTableWithDescriptor:tableDescriptor stage:MTLRenderStageFragment];
-
5:14 - Populate intersection function table
id<MTLFunctionHandle> handle; for (NSUInteger i = 0 ; i < functions.count ; i++) { // Get a handle to the linked intersection function in the pipeline state handle = [rayPipeline functionHandleWithFunction:functions[i] stage:MTLRenderStageFragment]; // Insert the function handle into the table [table setFunction:handle atIndex:i]; }
-
5:48 - Bind resources
[renderEncoder setFragmentAccelerationStructure:accelerationStructure atBufferIndex:0]; [renderEncoder setFragmentIntersectionFunctionTable:table atBufferIndex:1];
-
5:57 - Intersect from fragment shader
[[fragment]] float4 rayFragmentShader(vertex_output vo [[stage_in]], primitive_acceleration_structure accelerationStructure, intersection_function_table<triangle_data> functionTable, /* ... */) { // generate ray, create intersector... intersection = intersector.intersect(ray, accelerationStructure, functionTable); // shading... }
-
9:32 - Triangle intersection function
[[intersection(triangle, triangle_data)]] bool alphaTestIntersectionFunction(uint primitiveIndex [[primitive_id]], uint geometryIndex [[geometry_id]], float2 barycentricCoords [[barycentric_coord]], device Material *materials [[buffer(0)]]) { texture2d<float> alphaTexture = materials[geometryIndex].alphaTexture; float2 UV = interpolateUVs(materials[geometryIndex].UVs, primitiveIndex, barycentricCoords); float alpha = alphaTexture.sample(sampler, UV).x; return alpha > 0.5f; }
-
10:36 - Custom intersection with intersection query
intersection_query<instancing, triangle_data> iq(ray, as, params); // Step 1: start traversing acceleration structure while (iq.next()) { // Step 2: candidate was found. Check type and run custom intersection. switch (iq.get_candidate_intersection_type()) { case intersection_type::triangle: { bool alphaTestResult = alphaTest(iq.get_candidate_geometry_id(), iq.get_candidate_primitive_id(), iq.get_candidate_triangle_barycentric_coord()); // Step 3: commit candidate or ignore if (alphaTestResult) iq.commit_triangle_intersection() } } }
-
10:39 - Custom intersection with intersection query 2
switch (iq.get_committed_intersection_type()) { // Miss case case intersection_type::none: { missShading(); break; } // Triangle intersection was committed. Query some info and do shading. case intersection_type::triangle: { shadeHitTriangle(iq.get_committed_instance_id(), iq.get_committed_distance(), iq.get_committed_triangle_barycentric_coord()); break; } }
-
15:30 - Specifying user instance IDs
// New instance descriptor type typedef struct { uint32_t userID; // Members from MTLAccelerationStructureInstanceDescriptor... } MTLAccelerationStructureUserIDInstanceDescriptor; // Specify instance descriptor type through acceleration structure descriptor accelDesc.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeUserID;
-
15:47 - Retrieving user instance IDs 1
// Available in intersection functions [[intersection(bounding_box, instancing)]] IntersectionResult sphereInstanceIntersectionFunction(unsigned int userID[[user_instance_id]], /** other args **/) { // ... }
-
15:58 - Retrieving user instance IDs 2
// Available from intersection result intersection_result<instancing> intersection = instanceIntersector.intersect(/* args */); if (intersection.type != intersection_type::none) instanceIndex = intersection.user_instance_id; // Available from intersection query intersection_query<instancing> iq(/* args */); iq.next() if (iq.get_committed_intersection_type() != intersection_type::none) instanceIndex = iq.get_committed_user_instance_id();
-
16:36 - Instance transforms
// Available in intersection functions [[intersection(bounding_box, instancing, world_space_data)]] IntersectionResult intersectionFunction(float4x3 objToWorld [[object_to_world_transform]], float4x3 worldToObj [[world_to_object_transform]], /** other args **/) { // ... }
-
16:51 - Instance transforms 2
// Available from intersection result intersection_result<instancing, world_space_data> result = intersector.intersect(/* args */); if (result.type != intersection_type::none) { output.myObjectToWorldTransform = result.object_to_world_transform; output.myWorldToObjectTransform = result.world_to_object_transform; }
-
17:03 - Instance transforms 3
// Available from intersection query intersection_query<instancing> iq(/* args */); iq.next() if(iq.get_committed_intersection_type() != intersection_type::none){ output.myObjectToWorldTransform = iq.get_committed_object_to_world_transform(); output.myWorldToObjectTransform = iq.get_committed_world_to_object_transform(); }
-
19:17 - Extended limits
// Specify through acceleration structure descriptor accelDesc.usage = MTLAccelerationStructureUsageExtendedLimits; // Specify intersector tag intersector<extended_limits> extendedIntersector;
-
22:30 - Sampling time
// Randomly sample time float time = random(exposure_start, exposure_end); result = intersector.intersect(ray, acceleration_structure, time);
-
25:54 - Motion instance descriptor
descriptor = [MTLInstanceAccelerationStructureDescriptor new]; descriptor.instanceDescriptorType = MTLAccelerationStructureInstanceDescriptorTypeMotion; // Buffer containing motion instance descriptors descriptor.instanceDescriptorBuffer = instanceBuffer; descriptor.instanceCount = instanceCount; // Buffer containing MTLPackedFloat4x3 transformation matrices descriptor.motionTransformBuffer = transformsBuffer; descriptor.motionTransformCount = transformCount; descriptor.instancedAccelerationStructures = primitiveAccelerationStructures;
-
26:33 - Instance motion
// Specify intersector tag kernel void raytracingKernel(acceleration_structure<instancing, instance_motion> as, /* other args */) { intersector<instancing, instance_motion> intersector; // ... }
-
27:24 - Primitive motion 1
// Collect keyframe vertex buffers NSMutableArray<MTLMotionKeyframeData*> *vertexBuffers = [NSMutableArray new]; for (NSUInteger i = 0 ; i < keyframeBuffers.count ; i++) { MTLMotionKeyframeData *keyframeData = [MTLMotionKeyframeData data]; keyframeData.buffer = keyframeBuffers[i]; [vertexBuffers addObject:keyframeData]; }
-
27:39 - Primitive motion 2
// Create motion geometry descriptor MTLAccelerationStructureMotionTriangleGeometryDescriptor *geometryDescriptor = [MTLAccelerationStructureMotionTriangleGeometryDescriptor descriptor]; geometryDescriptor.vertexBuffers = vertexBuffers; geometryDescriptor.triangleCount = triangleCount;
-
27:57 - Primitive motion 3
// Create acceleration structure descriptor MTLPrimitiveAccelerationStructureDescriptor *primitiveDescriptor = [MTLPrimitiveAccelerationStructureDescriptor descriptor]; primitiveDescriptor.geometryDescriptors = @[ geometryDescriptor ]; primitiveDescriptor.motionKeyframeCount = keyframeCount;
-
28:10 - Primitive motion 4
// Specify intersector tag kernel void raytracingKernel(acceleration_structure<primitive_motion> as, /* other args */) { intersector<primitive_motion> intersector; // ... }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。