No problem. The shader binding table is a central topic which must be understood or nothing will work.
Note that when I talked about reading the vertex attributes and indices data from an SBT hit record above, I was thinking of an SBT with a hit record per OptixInstance.
Without an instance acceleration structure (IAS), means only using a single geometry acceleration structure (GAS) as the scene, things will be a lot less flexible and the SBT hit records can naturally be used to store the required data.
I use an IAS->GAS scene structure in my OptiX 7 examples and an SBT entry per instance because that allowed changing shaders (SBT hit record header) per instance without updating the IAS because nothing changed in the OptixInstances.
This is kind of wasteful when having few materials and many instances (e.g. millions).
I would recommend implementing that differently today to simplify the SBT handling.
There is another elegant method to index into the SBT for the material and hold the per instance data separately.
The SBT hit records only need to contain the 32 byte header information which selects the material programs defining the material behavior (bi-directional scattering distribution function, BSDF), but none of the input parameters.
Which material is used can be directly selected with the OptixInstance sbtOffset
value.
All other data required to define an OptixInstance’s geometry topology (vertex attributes and indices) and any other data like material parameters can be stored in separate device memory arrays and uniquely indexed by the user defined OptixInstance instanceId
field which can be read inside the device code with optixGetInstanceId() which is available in IS, AH, and CH programs.
Note that there is also the optixGetInstanceIndex()
which returns the zero based index inside an IAS. Means when the scene is using a single IAS as the root (implies OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING
) that would be another unique per instance index which could be used to access custom data in device memory.
Now, changing material parameters of such an instance would only need to update the material parameter buffer of that instance.
(That’s normally done by copying data from host to device with a CUDA host functions, but that could even be done in a kernel on the device since it’s just some device memory pointer. Just in case you’d ever need to animate a huge number of material parameters programmatically.)
Switching the instance’s material shader (BSDF) would need to set a different sbtOffset
and update the IAS with optixAccelBuild(). Though that’s a pretty fast operation.
That would provide the smallest possible shader binding table while having all remaining flexibilty offered by OptixInstances.
Think of this example:
A material library has three different shaders for wood: matte, oiled, coated.
But there are many different kinds of wood types (textures) in that material library and each can be used with the matte, oiled, and coated wood shaders.
Means you would only need three hit records in the SBT for the different shaders, but can have arbitrary many material instances with different input parameters when indexing these via the OptixInstance instanceId
.
The design of the SBT boils down to the available inputs for the SBT index calculation formula and what an application requires.
https://raytracing-docs.nvidia.com/optix7/guide/index.html#shader_binding_table#acceleration-structures
It’s your choice how to architect that in the application. The SBT is very flexible to allow handling of different application requirements, and we haven’t even talked about multiple SBT entries per GAS.