How rayQueryGetIntersectionTEXT Works in GLSL
This article explains how the
rayQueryGetIntersectionTEXT function retrieves the
parametric hit distance (\(t\)) during
ray query execution in GLSL using the GL_EXT_ray_query
extension. It covers the underlying mathematical ray representation, how
the hardware tracks intersection states, the distinction between
candidate and committed hits, and a practical implementation
example.
The Parametric Ray Equation and Hit Distance
Ray tracing engines represent a ray mathematically using the parametric line equation:
\[\mathbf{P}(t) = \mathbf{O} + t \cdot \mathbf{D}\]
Where:
- \(\mathbf{O}\) is the ray origin
(
rayQueryGetIntersectionRayOriginEXT). - \(\mathbf{D}\) is the ray direction
(
rayQueryGetIntersectionRayDirectionEXT). - \(t\) is the scalar parametric distance along the ray.
When a ray intersects geometry (such as an axis-aligned bounding box
or a triangle), the intersection hardware calculates the exact value of
\(t\) where the intersection takes
place. The function rayQueryGetIntersectionTEXT retrieves
this calculated scalar \(t\) value
directly from internal hardware ray query registers.
Function Signature and Parameters
The GLSL intrinsic is defined as:
float rayQueryGetIntersectionTEXT(rayQueryEXT rayQuery, bool committed);The function takes two parameters:
rayQuery: The ray query traversal object tracking state.committed: A boolean flag determining which intersection register to read from:false(Candidate Intersection): Reads the hit distance of the candidate geometry currently being evaluated. This is used during traversal when processing non-opaque geometry or custom intersection shaders to evaluate whether a hit should be accepted or rejected.true(Committed Intersection): Reads the hit distance of the closest accepted intersection confirmed so far. Once traversal completes, this returns the final, confirmed hit distance along the ray.
Internal Traversal Mechanism
- Initialization: The ray is launched with
rayQueryInitializeEXT, establishing \(t_{\min}\) and \(t_{\max}\) bounds. - Traversal Steps: During
rayQueryProceedEXT, the ray traversal unit tests nodes in the acceleration structure. When a primitive falls within current \(t\) bounds:- The candidate hit distance is updated in hardware scratch memory.
- If non-opaque, execution yields back to the shader. Calling
rayQueryGetIntersectionTEXT(rayQuery, false)returns this candidate \(t\) value.
- Commitment: If the hit is confirmed (either
automatically for opaque primitives or via
rayQueryConfirmIntersectionEXT), the candidate \(t\) becomes the new active \(t_{\max}\) limit for subsequent tests, and the committed register is updated. - Final Result: After
rayQueryProceedEXTreturnsfalse,rayQueryGetIntersectionTEXT(rayQuery, true)retrieves the scalar \(t\) of the closest confirmed hit.
Practical Implementation
The following example demonstrates how to extract the hit distance after traversing an acceleration structure:
#version 460
#extension GL_EXT_ray_query : require
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
void main() {
rayQueryEXT rayQuery;
vec3 origin = vec3(0.0, 1.0, 0.0);
vec3 direction = vec3(0.0, 0.0, 1.0);
float tMin = 0.001;
float tMax = 1000.0;
// Initialize the query
rayQueryInitializeEXT(
rayQuery,
topLevelAS,
gl_RayFlagsOpaqueEXT,
0xFF,
origin,
tMin,
direction,
tMax
);
// Process all intersections
while (rayQueryProceedEXT(rayQuery)) {
// For candidate intersections (if handling non-opaque geometry)
float candidateT = rayQueryGetIntersectionTEXT(rayQuery, false);
}
// Check if an intersection was committed
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) {
// Retrieve the final parametric hit distance
float hitT = rayQueryGetIntersectionTEXT(rayQuery, true);
vec3 hitPosition = origin + hitT * direction;
}
}Physical Distance vs. Parametric \(t\)
The scalar returned by rayQueryGetIntersectionTEXT
represents world-space Euclidean distance only if the
ray direction vector (\(\mathbf{D}\))
supplied to rayQueryInitializeEXT is normalized.
If the direction vector has a length other than \(1.0\), the actual physical distance to the hit point must be computed as:
\[\text{Distance} = t \cdot \|\mathbf{D}\|\]
Normalizing the direction vector prior to ray initialization ensures
that rayQueryGetIntersectionTEXT directly reflects true
world-space units.