rayQueryGetIntersectionBarycentricsEXT in GLSL Ray Queries
This article explains how the
rayQueryGetIntersectionBarycentricsEXT intrinsic retrieves
triangle barycentric coordinates within inline GLSL ray queries using
the GL_EXT_ray_query extension. It covers the function's
signature, how the returned two-dimensional floating-point vector maps
to a 3D triangle, the distinction between candidate and committed
intersections, and how to use these coordinates to interpolate
per-vertex attributes accurately.
Function Signature and Parameters
The rayQueryGetIntersectionBarycentricsEXT function is
provided by the GL_EXT_ray_query SPIR-V extension for
Vulkan. It extracts the hit location on a triangle primitive directly
from a ray query object. Its signature is:
vec2 rayQueryGetIntersectionBarycentricsEXT(rayQueryEXT rayQuery, bool committed);The function takes two arguments:
rayQuery: The initializedrayQueryEXTobject handling the traversal.committed: A boolean flag determining which intersection state to read. Passingfalseinspects the current candidate intersection while traversing. Passingtrueinspects the final committed intersection after traversal concludes or when accepting a hit.
The Returned Barycentric Format
The function returns a vec2 rather than a
vec3. Ray tracing hardware and low-level APIs (such as
Vulkan and DirectX Raytracing) follow standard normalized barycentric
conventions for triangles:
- The returned
xcomponent corresponds to the weight of vertex 1 (\(u\)). - The returned
ycomponent corresponds to the weight of vertex 2 (\(v\)). - The weight of vertex 0 (\(w\)) is implicit, calculated as \(1.0 - u - v\).
The sum of all three barycentric weights always equals
1.0:
\[w = 1.0 - uv.x - uv.y\]
Retrieving and Interpolating Attributes
To interpolate vertex attributes such as texture coordinates, normals, or colors, you must fetch the corresponding vertex data from storage buffers using the primitive index and multiply them by their respective barycentric weights.
// Ensure the hit is a triangle
if (rayQueryGetIntersectionTypeEXT(rq, true) == gl_RayQueryCommittedIntersectionTriangleEXT) {
// 1. Retrieve the two barycentric coordinates
vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, true);
// 2. Compute the third coordinate
float w = 1.0 - bary.x - bary.y;
vec3 weights = vec3(w, bary.x, bary.y);
// 3. Fetch vertex attributes (e.g., UV coordinates from a buffer)
int primID = rayQueryGetIntersectionPrimitiveIndexEXT(rq, true);
vec2 uv0 = vertices[indices[primID * 3 + 0]].uv;
vec2 uv1 = vertices[indices[primID * 3 + 1]].uv;
vec2 uv2 = vertices[indices[primID * 3 + 2]].uv;
// 4. Interpolate across the triangle surface
vec2 hitUV = uv0 * weights.x + uv1 * weights.y + uv2 * weights.z;
}Candidate vs. Committed Intersections
The behavior of rayQueryGetIntersectionBarycentricsEXT
depends on the traversal stage:
- Candidate Intersections
(
committed = false): Used inside thewhile(rayQueryProceedEXT(rayQuery))loop when handling non-opaque triangles. If custom alpha testing or any-hit logic is required, you can query candidate barycentrics to sample alpha textures before deciding whether to callrayQueryConfirmIntersectionEXT(rayQuery). - Committed Intersections
(
committed = true): Used afterrayQueryProceedEXTreturnsfalse(meaning traversal is complete) or immediately after an intersection is confirmed. This yields the barycentrics of the closest confirmed hit along the ray.
Calling this function on an intersection type that is not a triangle
(such as an AABB procedural primitive or a miss) produces undefined
results. Always verify the intersection type with
rayQueryGetIntersectionTypeEXT before reading barycentric
data.