The specific meaning of offset and stride in optixTrace

In my understanding, the SBT offset parameter in optixTrace represents the index of the hitgroup SBT for the current trace call, and missSBTIndex represents the index of the missgroup SBT for the current trace call. So does the SBT stride actually have any functional effect, or does it only serve as a symbolic and informative role? For example, would the two pieces of code below essentially have the same effect, with SBT stride not playing a functional role?

optixTrace(
        handle,
        ray_origin, ray_dir,
        0.0f, 1e16f,
        0.0f,              // rayTime
        OptixVisibilityMask(1),
        OPTIX_RAY_FLAG_NONE,
        0,                 // SBT offset
        2,                 // SBT stride
        0                  // missSBTIndex
    );

 optixTrace(
        handle,
        ray_origin, ray_dir,
        0.0f, 1e16f,
        0.0f,              // rayTime
        OptixVisibilityMask(1),
        OPTIX_RAY_FLAG_NONE,
        0,                 // SBT offset
        3,                 // SBT stride
        0                  // missSBTIndex
    );

Hello. The common use of SBT stride and offset is to implement multiple ray types. For instance, having separate shadow rays and radiance rays is common when path tracing. These two logical types of rays would need to invoke different hit-programs (and possibly miss programs) since they perform different operations when shading.

To implement such a system, you would generate an SBT with two hit groups per material, rather than one. One hit program group would perform lighting calculations for the radiance rays and the other might check opacity for shadow rays. When calling optixTraceyou would need to inform optix which hit-programs this particular ray would use. The stride tells optix how many ray types exist (in this case 2) and the offset would tell optix which ray type this particular ray belongs to (might be zero for radiance rays and one for shadow rays, but this depends on what order you used in your SBT). Functionally, the stride allows optix to correctly index into the SBT array since you have multiple hit groups per material.

Note that the SDK uses only a single ray-type for its samples so SBT offset is always 0 and SBT stride is 1. However we do still often use named variables to indicate the semantics of these parameters:

    optixTrace(
            handle,
            ray_origin,
            ray_direction,
            0.0f,                     // tmin
            1e16f,                    // tmax
            ray_time,
            OptixVisibilityMask( 1 ),
            OPTIX_RAY_FLAG_NONE,
            RAY_TYPE_RADIANCE,        // SBT offset
            RAY_TYPE_COUNT,           // SBT stride
            RAY_TYPE_RADIANCE,        // missSBTIndex
            r, g, b );
1 Like

Also, if you want to see the somewhat technical details of how SBT Index and Stride are applied, please take a look at chapter 7 of the OptiX Programming Guide. Section 7.3 gives the following formula for how the SBT index is computed by optix after intersection:

sbt-index =
    sbt-instance-offset
    + (sbt-geometry-acceleration-structure-index * sbt-stride-from-trace-call)
    + sbt-offset-from-trace-call
1 Like

If you only call optixAccelBuild once in a case like this, it basically means there’s just one geometry acceleration structure, so the sbt-geometry-acceleration-structure-index defaults to 0. In this situation, no matter what value you set for sbt-stride, it gets multiplied by 0, so it doesn’t really affect the result. Does that mean only sbt-offset actually matters?

Yes, in this case you only have a single GAS, so the sbt-geometry-acceleration-structure-index will always be zero. But you want your shaders to be decoupled from the input geometry hierarchy. If you decided to add a second GAS, then your shader would give incorrect results unless the stride is correct.