rayQueryGetIntersectionTypeEXT Candidate vs Committed Hits

In Vulkan ray tracing using GLSL, rayQueryGetIntersectionTypeEXT determines whether a ray has intersected geometry and identifies the kind of geometry encountered. Rather than using separate functions to distinguish between temporary candidate hits and final committed hits, the function relies on a explicit boolean parameter passed by the developer. This article explains how this boolean parameter operates within the ray query lifecycle, how candidate and committed states differ, and the return values associated with each state.

The Function Signature and Parameter

The GLSL function signature defined by the GL_EXT_ray_query extension is:

uint rayQueryGetIntersectionTypeEXT(rayQueryEXT rayQuery, bool committed);

The function differentiates candidate hits from committed hits solely through the second parameter, committed:

  • committed = false: Evaluates the current candidate intersection.
  • committed = true: Evaluates the currently committed (confirmed) intersection.

Understanding Candidate Hits (committed = false)

A candidate hit represents an unconfirmed intersection encountered while traversing the acceleration structure. Traversal pauses at a candidate hit whenever the ray query encounters geometry that requires shader intervention, such as non-opaque geometry or procedural AABBs.

When rayQueryProceedEXT(rayQuery) returns true, traversal has temporarily yielded control back to the shader. At this stage, querying with committed = false returns the geometry type of the hit under evaluation:

  • rayQueryIntersectionTriangleEXT: A candidate triangle has been hit. For non-opaque triangles, the shader can inspect properties (like alpha testing) and choose whether to call rayQueryConfirmIntersectionEXT() to commit the hit.
  • rayQueryIntersectionGeneratedEXT: An axis-aligned bounding box (AABB) for a procedural primitive has been reached. The shader must perform custom intersection logic and potentially commit a hit using rayQueryGenerateIntersectionEXT().

If committed = false is passed when no candidate is currently active, the function returns rayQueryIntersectionNoneEXT.

Understanding Committed Hits (committed = true)

A committed hit represents an intersection that has been accepted as valid. For opaque geometry, the hardware traversal engine automatically commits the intersection. For non-opaque or procedural geometry, it represents a candidate that the shader explicitly confirmed.

Querying with committed = true inspects the best valid hit found so far:

  • Inside the traversal loop: It returns the state of the closest confirmed hit up to the current point of execution.
  • After the traversal loop terminates: When rayQueryProceedEXT() returns false, traversal is complete. Calling rayQueryGetIntersectionTypeEXT(rayQuery, true) reveals the final result of the entire ray query.

The return values for committed queries are:

  • rayQueryIntersectionNoneEXT: No valid intersection was committed (a miss).
  • rayQueryIntersectionTriangleEXT: The final committed hit is a triangle.
  • rayQueryIntersectionGeneratedEXT: The final committed hit is a procedural primitive.

Typical Execution Pattern

In practice, the distinction controls the flow within a ray query:

rayQueryEXT rq;
rayQueryInitializeEXT(rq, topLevelAS, rayFlags, cullMask, origin, tMin, direction, tMax);

while (rayQueryProceedEXT(rq)) {
    // Inspect candidate hit to make confirmation decisions
    if (rayQueryGetIntersectionTypeEXT(rq, false) == rayQueryIntersectionTriangleEXT) {
        // Perform alpha testing or custom opacity logic
        if (shouldAcceptHit()) {
            rayQueryConfirmIntersectionEXT(rq);
        }
    }
}

// Inspect the final committed hit after traversal finishes
if (rayQueryGetIntersectionTypeEXT(rq, true) != rayQueryIntersectionNoneEXT) {
    // Shade the confirmed hit
}

By toggling the boolean flag, rayQueryGetIntersectionTypeEXT cleanly separates the transient evaluation state during traversal from the persistent, confirmed hit record.