How to index STB record in each OptixBuildInput in Optix7?

It’s seems every BuildInput can bond to multiple STB record by designate the value:

xxxInput.triangleArray.numSbtRecords;

But I see a annotation in optix_7_types.h that the size of sbtIndexOffsetBuffer needs to be the number of primitives?

Does that means I must let the number of SBT record be one or equal the amounts of primitives in each BuildInput?

If you have multiple SBT records per geometry acceleration structure (GAS), you need to use the sbtIndexOffsetBuffer to select which primitive in your GAS accesses which SBT record.
Means the sbtIndexOffsetBuffer must contain as many offsets as there are primitives inside your GAS and the values must be in the range [0, numSbtRecords-1].

This is normally used to select the material per primitive and multiple OptiX SDK examples, like the optixPathTracer, contain something like the below code in the sources.
If you search for g_mat_indices, you’ll see that this array contains unsigned integer values for each triangle in the single GAS that app is using in the simply Cornell Box model.
Looks like this:

static std::array<uint32_t, TRIANGLE_COUNT> g_mat_indices = { {
    0, 0,                          // Floor         -- white lambert
    0, 0,                          // Ceiling       -- white lambert
    0, 0,                          // Back wall     -- white lambert
    1, 1,                          // Right wall    -- green lambert
    2, 2,                          // Left wall     -- red lambert
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // Short block   -- white lambert
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // Tall block    -- white lambert
    3, 3                           // Ceiling light -- emmissive
} };

and is then uploaded to the CUdeviceptr used inside the accelBuild() call in the function
void buildMeshAccel( PathTracerState& state )

Of course that is just a simple hardcoded example because the exact number of primitives inside the simple Cornell Box scene is known, but it works just like that when creating these offset values dynamically.

Please have a look at the explanations around Listing 5.4. here:
https://raytracing-docs.nvidia.com/optix7/guide/index.html#acceleration_structures#primitive-build-inputs
and especially the SBT example here:
https://raytracing-docs.nvidia.com/optix7/guide/index.html#shader_binding_table#sbt-gasa-index

The crucial formula to understand the SBT record indexing is the sbt-index calculation here which shows how all individual parameters from instance and geometry AS and the optixTrace() arguments are used together to calculate the resulting SBT index per ray:
https://raytracing-docs.nvidia.com/optix7/guide/index.html#shader_binding_table#acceleration-structures

thanks, this’s a very intutive explanation. I didn’t understand the usage of the ‘sbtInexOffsetBuffer’ at first.
Now I understand that each primitive in a single GAS is corresponding to a index-offset in sbtIndexOffsetBuffer .