
对于包含大量实例、共享网格或共享材质的 GPU 光线追踪应用,NVIDIA OptiX 的 Shader Binding Table(SBT)不应默认按实例重复保存完整着色数据。源资料说明,开发者可将实例级、几何级和材质级数据拆分存放,并利用 OptiX 查询函数完成查找,从而减少重复的 SBT 记录和着色数据。实际收益取决于场景实例数、唯一网格数、材质组合、光线类型及内存访问模式,应通过目标项目测试确认。
OptiX SBT 要解决什么问题
NVIDIA OptiX 是通过 CUDA 实现 GPU 加速光线追踪的 API。当光线与几何基元相交时,命中着色器需要确定应执行的程序,并取得法线、反射率、粗糙度等输入数据。SBT 用于将着色器程序及相关数据映射到相交处理过程。
在常见渲染场景中,应用通常同时维护几何信息和材质参数。若每个实例都在独立 SBT 记录中保存着色器引用、法线数据引用和材质参数,开发实现相对直接;但当多个实例复用同一网格或材质时,SBT 标头和数据块会产生重复存储。源资料指出,这类重复还可能增加主机端填充和维护大型 SBT 数组的工作,并影响 GPU 端内存访问效率。
两种 SBT 数据布局方式
按实例保存的直接布局
直接布局为每个实例及每种光线类型建立单独的 SBT 记录。记录头部关联着色器程序,用户定义的数据块保存几何数据引用和材质参数,较小的参数也可以直接内联。例如,法线数组可放在全局内存中,SBT 数据块仅保存其指针及反射率、粗糙度等参数。
这种方式适合简单应用、实例规模有限或优先降低初始实现复杂度的项目。但数据块必须容纳不同材质所需的最大参数集合,某些材质不使用的字段仍可能占用空间。源资料给出的假设场景包含 100,000 个实例、50,000 个唯一三角形网格和 10,000 个唯一材质参数集;在该示例的按实例布局中,SBT 及着色数据开销约为 6 MB。该数值是特定结构和对齐条件下的示例,不应直接用于其他项目容量规划。
按共享关系拆分的优化布局
优化方法首先从 SBT 记录中移除数据部分,将着色参数置于全局内存数组。应用可把实例 ID 设为该数组的索引,设备代码通过 optixGetInstanceId() 取得当前实例对应的参数。实例 ID 不要求在场景中唯一,因此共享相同几何和着色数据的实例可以指向同一条目。
随后可将不随实例变化的几何参数进一步绑定到 GAS。源资料说明,OptiX 8.1 引入的 optixGetGASPointerFromHandle 可取得 GAS 关联二进制加速结构数据的地址;应用可在构建 GAS 时于该内存前放置用户数据块,并在设备端据此读取几何参数。这样,法线数组等几何级数据可按 GAS 保存,而材质参数数组可按唯一材质参数保存。
适合采用优化布局的场景
- 场景含有大量实例,且多个实例复用相同网格、材质或着色参数。
- 材质类型数量有限,但每个材质被大量实例使用。
- 项目需要控制 SBT 数组规模,或希望减少实例数增长带来的重复数据。
- 团队能够维护实例 ID、材质参数索引、GAS 数据与 SBT 偏移量之间的明确映射。
在源资料的最终示例中,SBT 记录数仅取决于唯一材质着色器数;几何参数按 GAS 保存,材质参数按唯一材质参数保存。其存储关系可概括为:GAS 数量乘以 GeometryParams 大小,加上唯一材质实例数乘以 MaterialParams 大小,再加上材质着色器数乘以 OPTIX_SBT_RECORD_HEADER_SIZE。该思路的关键不是固定容量,而是让存储规模更多由共享资源数量决定,而非直接由实例总数决定。
实施与评估路径
- 盘点场景中的实例、GAS、材质参数集、几何类型和光线类型,识别可共享的数据。
- 先实现可验证的按实例 SBT 布局,确认命中程序、数据访问和渲染结果正确。
- 将材质参数迁移至全局数组,并定义实例 ID 到参数索引的映射规则。
- 评估是否将几何级数据与 GAS 关联;采用 optixGetGASPointerFromHandle 前,应确认所用 OptiX 版本及内存布局符合官方文档要求。
- 按材质类型设置 SBT 偏移量,并在引入多种几何类型或多种光线类型后重新核对命中组组合。
- 在目标 GPU、实际场景和完整渲染路径中测量显存占用、构建开销、更新成本及渲染表现。
扩展场景与实现边界
优化布局并不意味着 SBT 条目恒定不变。源资料指出,命中组通常包含几何相交程序和材质命中程序,因此多种几何类型会使 SBT 条目数量随“几何类型与材质着色器组合”增加;多种光线类型也会成为乘数。对于三种几何类型和两种材质,最多可有六个 SBT 命中组条目,而实际项目还需纳入光线类型。
若一个 GAS 内含多种材质,可使用辅助查找表,将实例 ID 和 SBT GAS 索引重定向到着色参数索引。可用的状态查询还包括 optixGetSBTDataPointer、optixGetInstanceIndex、optixGetPrimitiveIndex 和 optixGetSbtGASIndex。这些机制提供了更灵活的数据查找路径,但也增加了索引设计、内存生命周期管理和调试验证的要求。
常见问题
是否所有 OptiX 应用都应移除 SBT 数据块?
不一定。源资料明确将按实例保存 SBT 数据的方法视为简单应用和简单场景设置的合理选择。若实例数量不大、资源共享有限,或团队更看重实现直观性,直接布局可能更合适。应以实际 SBT 容量、更新频率和渲染测试结果决定。
使用 optixGetGASPointerFromHandle 时需要确认什么?
该函数在源资料中标注为 OptiX 8.1 引入。项目应核对已采用的 OptiX 版本、对应日期的 NVIDIA OptiX 编程文档、GAS 构建时的用户数据内存布局,以及设备端地址计算的正确性。不要仅依据示例假定其适用于所有版本、构建方式或几何类型。
结论
NVIDIA OptiX SBT 可用于直接绑定实例级着色器和数据,也可作为更精简的数据查找体系的一部分。对具有大量重复实例的光线追踪场景,将材质数据、几何数据和着色器记录按共享层级拆分,能够减少重复存储的可能性;但多光线类型、多几何类型、GAS 内多材质以及版本兼容性都会影响最终设计。应依据完整 SKU/BOM、官方产品文档和项目级测试验证内存布局及实际效果。
围绕“NVIDIA OptiX 着色器绑定表优化:减少光线追踪数据冗余”继续了解 NVIDIA 产品与网络方案。
WeChat
Profile