gl_RayFlagsSkipClosestHitShaderEXT for Occlusion Rays
In hardware-accelerated ray tracing pipelines using GLSL, evaluating
pure occlusion—such as shadow or ambient occlusion testing—requires
determining only whether an intersection exists along a ray rather than
computing detailed surface attributes. The
gl_RayFlagsSkipClosestHitShaderEXT flag streamlines this
process by instructing the ray tracing hardware to bypass the execution
of the Closest Hit Shader (CHS) entirely when an intersection is
confirmed. This article examines how this flag operates at the pipeline
level, how it interacts with ray payloads, and how combining it with
complementary traversal flags optimizes occlusion queries into fast,
fixed-function visibility checks.
The Inefficiency of the Closest Hit Shader in Occlusion Queries
In a standard ray tracing pipeline, rays identify the nearest surface interaction, after which the pipeline invokes the Closest Hit Shader associated with the hit geometry. The CHS typically evaluates lighting, materials, and secondary rays, writing the results into the ray payload.
For pure occlusion rays, however, the exact surface properties, texture coordinates, and lighting data of the occluder are irrelevant. The query only needs to yield a binary result: whether the ray path between the origin and the target is clear or blocked. Invoking a CHS for an occlusion ray introduces substantial latency by scheduling, launching, and executing unnecessary programmable shader stages and memory writes.
How
gl_RayFlagsSkipClosestHitShaderEXT Bypasses Execution
When gl_RayFlagsSkipClosestHitShaderEXT is passed to the
traceRayEXT() call in GLSL, it sets a hardware traversal
state that modifies how the pipeline handles ray termination:
- State Evaluation: During acceleration structure traversal, the hardware tests for ray-primitive intersections.
- Hit Confirmation: If the ray determines an intersection with an opaque surface (or passes the Any-Hit Shader test), the ray state is marked as having hit geometry.
- Execution Suppression: Under normal execution,
concluding traversal with an active hit triggers the binding and
execution of the corresponding hit group's CHS. Setting
gl_RayFlagsSkipClosestHitShaderEXTtells the pipeline to drop the CHS stage completely. - Control Return: Traversal halts without invoking any shader code from the hit group, returning execution directly to the calling shader (typically the Ray Generation Shader) or transferring state back to the caller.
Payload Management for Binary Visibility
Because the Closest Hit Shader does not run, it cannot be relied upon to write data to the ray payload indicating an occlusion event. Instead, the application determines visibility using initialization patterns or the Miss Shader:
- Miss-Shader Strategy: The Ray Generation Shader
initializes the ray payload to represent an occluded state (e.g.,
visibility = 0.0). If the ray encounters geometry, the CHS is skipped, leaving the payload as0.0. If the ray encounters no geometry along its path, the Miss Shader executes and updates the payload to represent an unoccluded state (e.g.,visibility = 1.0). - Direct Ray Queries: When using inline ray queries
(
rayQueryEXT), skipping hit shaders avoids pipeline state transitions entirely, letting fixed-function hardware handle the query while the calling shader checksrayQueryGetIntersectionTypeEXT().
Pairing Flags for Maximum Traversal Throughput
To achieve zero programmable shader overhead for pure occlusion,
gl_RayFlagsSkipClosestHitShaderEXT is combined with other
ray flags:
gl_RayFlagsTerminateOnFirstHitEXT: Forces the traversal unit to stop immediately upon encountering the first valid intersection rather than searching for the true closest hit along the ray interval.gl_RayFlagsOpaqueEXT: Treats all geometry as fully opaque, bypassing Any-Hit Shader invocations.
When gl_RayFlagsSkipClosestHitShaderEXT,
gl_RayFlagsTerminateOnFirstHitEXT, and
gl_RayFlagsOpaqueEXT are used together, the ray traversal
operates entirely within fixed-function hardware. Any-Hit shaders are
skipped, traversal aborts on the first primitive encountered, and the
Closest Hit Shader never launches. This turns occlusion testing into a
highly optimized, hardware-accelerated boolean operation.