33. Ray Traversal
The ray traversal process identifies and handles intersections between a ray and geometries in an acceleration structure.
Ray traversal cannot be started by a Vulkan API command directly  a shader
must execute
OpRayQueryProceedKHR
or
OpTraceRayKHR
.
When the rayTracingPipeline
feature is
enabled, OpTraceRayKHR
can be used for ray tracing in
a ray tracing pipeline.
When the rayQuery
feature is enabled,
OpRayQueryProceedKHR
can be used in any shader stage.
33.1. Ray Intersection Candidate Determination
Once tracing begins, rays are first tested against instances in a toplevel acceleration structure. A ray that intersects an instance will be transformed into the space of the instance to continue traversal within that instance; therefore the transform matrix stored in the instance must be invertible.
Next, rays are tested against geometries in an bottomlevel acceleration structure to determine if a hit occurred between them, initially based only on their geometric properties (i.e. their vertices). The implementation performs similar operations to that of rasterization, but with the effective viewport determined by the parameters of the ray, and the geometry transformed into a space determined by that viewport.
The vertices of each primitive are transformed from acceleration structure space _{as} to ray space _{r} according to the ray origin and direction as follows:
$a$ is the axis of rotation from the unnormalized ray direction vector $d$ to the axis vector $k$:
$s$ and $c$ are the sine and cosine of the angle of rotation about $a$ from $d$ to $k$:
$k$ is the unit vector:
$o$ and $d$ are the ray origin and unnormalized direction, respectively; the vector described by x_{as}, y_{as}, and z_{as} is any position in acceleration structure space; and the vector described by x_{r}, y_{r}, and z_{r} is the same position in ray space.
An intersection candidate is a unique point of intersection between a ray and a geometric primitive. For any primitive that has within its bounds a position $xyz_{as}$ such that
(where $t=∣∣d∣∣−z_{r} $), an intersection candidate exists.
Triangle primitive bounds consist of all points on the plane formed by the three vertices and within the bounds of the edges between the vertices, subject to the watertightness constraints below. AABB primitive bounds consist of all points within an implementationdefined bound which includes the specified box.
Note
The bounds of the AABB including all points internal to the bound implies that a ray started within the AABB will hit that AABB. 
The determination of this condition is performed in an implementation specific manner, and may be performed with floating point operations. Due to the complexity and number of operations involved, inaccuracies are expected, particularly as the scale of values involved begins to diverge. Implementations should take efforts to maintain as much precision as possible.
Note
One very common case is when geometries are close to each other at some distance from the origin in acceleration structure space, where an effect similar to “zfighting” is likely to be observed. Applications can mitigate this by ensuring their detailed geometries remain close to the origin. Another likely case is when the origin of a ray is set to a position on a previously intersected surface, and its t_{min} is zero or near zero; an intersection may be detected on the emitting surface. This case can usually be mitigated by offsetting t_{min} slightly. 
In the case of AABB geometries, implementations may increase their size in an acceleration structure in order to mitigate precision issues. This may result in false positive intersections being reported to the application.
For triangle intersection candidates, the b and c
barycentric coordinates on the triangle
where the above condition is met are made available to future shading.
If the ray was traced with OpTraceRayKHR
, these values are available as
a vector of 2 32bit floating point values in the HitAttributeKHR
storage class.
Once an intersection candidate is determined, it proceeds through the following operations, in order:
The sections below describe the exact details of these tests. There is no ordering guarantee between operations performed on different intersection candidates.
33.1.1. Watertightness
For a set of triangles with identical transforms, within a single instance:

Any set of two or more triangles where all triangles have one vertex with an identical position value, that vertex is a shared vertex.

Any set of two triangles with two shared vertices that were specified in the same winding order in each triangle have a shared edge defined by those vertices.
A closed fan is a set of three or more triangles where:

All triangles in the set have the same shared vertex as one of their vertices.

All edges that include the above vertex are shared edges.

All above shared edges are shared by exactly two triangles from the set.

No two triangles in the set intersect, except at shared edges.

Every triangle in the set is joined to every other triangle in the set by a series of the above shared edges.
Implementations should not doublehit or miss when a ray intersects a shared edge, or a shared vertex of a closed fan.
33.2. Ray Intersection Culling
Candidate intersections go through several phases of culling before confirmation as an actual hit. There is no particular ordering dependency between the different culling operations.
33.2.1. Ray Primitive Culling
If the rayTraversalPrimitiveCulling
or rayQuery
features are enabled, the SkipTrianglesKHR
and
SkipAABBsKHR
ray flags can be specified when tracing a ray.
If SkipTrianglesKHR
was included in the Ray Flags
operand of the ray
trace instruction, and the intersection is with a triangle primitive, the
intersection is dropped, and no further processing of this intersection
occurs.
If VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR
was included
in the pipeline, traversal with OpTraceRayKHR
calls will all behave as
if SkipTrianglesKHR
was included in its Ray Flags
operand.
If SkipAABBsKHR
was included in the Ray Flags
operand of the ray
trace instruction, and the intersection is with an AABB primitive, the
intersection is dropped, and no further processing of this intersection
occurs.
If VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR
was included in
the pipeline, traversal with OpTraceRayKHR
calls will all behave as if
SkipAABBsKHR
was included in its Ray Flags
operand.
33.2.2. Ray Mask Culling
Instances can be made invisible to particular rays based on the value of
VkAccelerationStructureInstanceKHR::mask
used to add that
instance to a toplevel acceleration structure, and the Cull Mask
parameter used to trace the ray.
For the instance which is intersected, if mask
& Cull Mask
==
0, the intersection is dropped, and no further processing occurs.
33.2.3. Ray Face Culling
As in polygon rasterization, one of the stages of ray traversal is to determine if a triangle primitive is back or frontfacing, and primitives can be culled based on that facing.
If the intersection candidate is with an AABB primitive, this operation is skipped.
When a ray intersects a triangle primitive, the order that vertices are specified for the polygon affects whether the ray intersects the front or back face. Front or back facing is determined in the same way as they are for rasterization, based on the sign of the polygon’s area but using the ray space coordinates instead of framebuffer coordinates. One way to compute this area is:
where $x_{r}$ and $y_{r}$ are the x and y ray space coordinates of the ith vertex of the nvertex polygon (vertices are numbered starting at zero for the purposes of this computation) and i ⊕ 1 is (i + 1) mod n.
By default, if a is negative then the intersection is with the front
face of the triangle, otherwise it is with the back face.
If VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR
is included in
VkAccelerationStructureInstanceKHR::flags
for the instance
containing the intersected triangle, this determination is reversed.
Additionally, if a is 0, the intersection candidate is treated as not
intersecting with any face, irrespective of the sign.
Note
In a lefthanded coordinate system, an intersection will be with the front
face of a triangle if the vertices of the triangle, as defined in index
order, appear from the ray’s perspective in a clockwise rotation order.

If the ray was traced with OpTraceRayKHR
, the HitKindKHR
builtin
is set to HitKindFrontFacingTriangleKHR
if the intersection is with
frontfacing geometry, and HitKindBackFacingTriangleKHR
if the
intersection is with backfacing geometry, for shader stages considering
this intersection.
If the ray was traced with OpRayQueryProceedKHR
,
OpRayQueryGetIntersectionFrontFaceKHR
will return true for intersection
candidates with front faces, or false for back faces.
If CullBackFacingTrianglesKHR
was included in the Ray Flags
parameter
of the ray trace instruction, and the intersection is determined as with the
back face of a triangle primitive, the intersection is dropped, and no
further processing of this intersection occurs.
If CullFrontFacingTrianglesKHR
was included in the Ray Flags
parameter of the ray trace instruction, and the intersection is determined
as with the front face of a triangle primitive, the intersection is dropped,
and no further processing of this intersection occurs.
This culling is disabled if
VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR
was included
in VkAccelerationStructureInstanceKHR::flags
for the instance
which the intersected geometry belongs to.
Intersection candidates that have not intersected with any face (a == 0) are unconditionally culled, irrespective of ray flags and geometry instance flags.
33.2.4. Ray Opacity Culling
Each geometry in the acceleration structure may be considered either opaque or not. Opaque geometries continue through traversal as normal, whereas nonopaque geometries need to be either confirmed or discarded by shader code. Intersection candidates can also be culled based on their opacity.
Each individual intersection candidate is initally determined as opaque if
VK_GEOMETRY_OPAQUE_BIT_KHR
was included in the
VkAccelerationStructureGeometryKHR::flags
when the geometry it
intersected with was built, otherwise it is considered nonopaque.
If the intersection candidate was generated by an intersection shader, the intersection is initially considered to have opacity matching the AABB candidate that it was generated from.
However, this opacity can be overridden when it is built into an instance.
Setting VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR
in
VkAccelerationStructureInstanceKHR::flags
will force all
geometries in the instance to be considered opaque.
Similarly, setting VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR
will
force all geometries in the instance to be considered nonopaque.
This can again be overridden by including OpaqueKHR
or NoOpaqueKHR
in the Ray Flags
parameter when tracing a ray.
OpaqueKHR
forces all geometries to behave as if they are opaque,
regardless of their build parameters.
Similarly, NoOpaqueKHR
forces all geometries to behave as if they are
nonopaque.
If the ray was traced with OpRayQueryProceedKHR
, to determine the
opacity of AABB intersection candidates,
OpRayQueryGetIntersectionCandidateAABBOpaqueKHR
can be used.
This instruction will return true
for opaque intersection candidates,
and false
for nonopaque intersection candidates.
If CullOpaqueKHR
is included in the Ray Flags
parameter when tracing
a ray, an intersection with a geometry that is considered opaque is dropped,
and no further processing occurs.
If CullNoOpaqueKHR
is included in the Ray Flags
parameter when
tracing a ray, an intersection with a geometry that is considered nonopaque
is dropped, and no further processing occurs.
33.3. Ray Intersection Confirmation
Depending on the opacity of intersected geometry and whether it is a triangle or an AABB, candidate intersections are further processed to determine the eventual hit result. Candidates generated from AABB intersections run through the same confirmation process as triangle hits.
33.3.1. AABB Intersection Candidates
For an intersection candidate with an AABB geometry generated by Ray Intersection Candidate Determination, shader code is executed to determine whether any hits should be reported to the traversal infrastructure; no further processing of this intersection candidate occurs. The occurrence of an AABB intersection candidate does not guarantee the ray intersects the primitive bounds. To avoid propagating false intersections the application should verify the intersection candidate before reporting any hits.
If the ray was traced with OpTraceRayKHR
, an intersection shader is invoked from the Shader Binding Table according
to the specified indexing for the
intersected geometry.
If this shader calls OpReportIntersectionKHR
, a new intersection
candidate is generated as described
below.
If the intersection shader is VK_SHADER_UNUSED_KHR
(which is only
allowed for a zero shader group) then no further processing of the
intersection candidate occurs.
Each new candidate generated as a result of this processing is a generated
intersection candidate that intersects the AABB geometry, with a t
value equal to the Hit
parameter of the OpReportIntersectionKHR
instruction.
The new generated candidate is then independently run through
Ray Intersection Confirmation as a
generated
intersection.
If the ray was traced with OpRayQueryProceedKHR
, control is returned to
the shader which executed OpRayQueryProceedKHR
, returning true
.
The resulting ray query has a candidate intersection type of
RayQueryCandidateIntersectionAABBKHR
.
OpRayQueryGenerateIntersectionKHR
can be called to commit a new
intersection candidate with committed intersection type of
RayQueryCommittedIntersectionGeneratedKHR
.
Further ray query processing can be continued by executing
OpRayQueryProceedKHR
with the same ray query, or intersection can be
terminated with OpRayQueryTerminateKHR
.
Unlike rays traced with OpTraceRayKHR
, candidates generated in this way
skip generated intersection candidate confirmation; applications should
make this determination before generating the intersection.
This operation may be executed multiple times for the same intersection candidate.
33.3.2. Triangle and Generated Intersection Candidates
For triangle and generated intersection candidates, additional shader code may be executed based on the intersection’s opacity.
If the intersection is opaque, the candidate is immediately confirmed as a valid hit and passes to the next stage of processing.
For nonopaque intersection candidates, shader code is executed to determine whether a hit occurred or not.
If the ray was traced with OpTraceRayKHR
, an anyhit
shader is invoked from the Shader Binding Table according to the
specified indexing.
If this shader calls OpIgnoreIntersectionKHR
, the candidate is dropped
and no further processing of the candidate occurs.
If the anyhit shader identified is
VK_SHADER_UNUSED_KHR
, the candidate is immediately confirmed as a
valid hit and passes to the next stage of processing.
If the ray was traced with OpRayQueryProceedKHR
, control is returned to
the shader which executed OpRayQueryProceedKHR
, returning true
.
As only triangle candidates participate in this operation with ray queries,
the resulting candidate intersection type is always
RayQueryCandidateIntersectionTriangleKHR
.
OpRayQueryConfirmIntersectionKHR
can be called on the ray query to
confirm the candidate as a hit with committed intersection type of
RayQueryCommittedIntersectionTriangleKHR
.
Further ray query processing can be continued by executing
OpRayQueryProceedKHR
with the same ray query, or intersection can be
terminated with OpRayQueryTerminateKHR
.
If OpRayQueryConfirmIntersectionKHR
has not been executed, the
candidate is dropped and no further processing of the candidate occurs.
This operation may be executed multiple times for the same intersection
candidate unless VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR
was specified for the intersected geometry.
33.4. Ray Closest Hit Determination
Unless the ray was traced with the TerminateOnFirstHitKHR
ray flag, the
implementation must track the closest confirmed hit until all geometries
have been tested and either confirmed or dropped.
After an intersection candidate is confirmed, its t value is compared to t_{max} to determine which intersection is closer, where t is the parametric distance along the ray at which the intersection occurred.

If t < t_{max}, t_{max} is set to t and the candidate is set as the current closest hit.

If t > t_{max}, the candidate is dropped and no further processing of that candidate occurs.

If t = t_{max}, the candidate may be set as the current closest hit or dropped.
If TerminateOnFirstHitKHR
was included in the Ray Flags
used to trace
the ray, once the first hit is confirmed, the ray trace is terminated.
33.5. Ray Result Determination
Once all candidates have finished processing the prior stages, or if the ray is forcibly terminated, the final result of the ray trace is determined.
If a closest hit result was identified by Ray Closest Hit Determination, a closest hit has occurred, otherwise the final result is a miss.
For rays traced with OpTraceRayKHR
, if a closest hit result was
identified, a closest hit shader is invoked from
the Shader Binding Table according to the
specified indexing for the
intersected geometry.
Control returns to the shader that executed OpTraceRayKHR
once this
shader returns.
This shader is skipped if either the ray flags included
SkipClosestHitShaderKHR
, or if the closest hit
shader identified is VK_SHADER_UNUSED_KHR
.
For rays traced with OpTraceRayKHR
where no hit result was identified,
the miss shader identified by the Miss Index
parameter
of OpTraceRayKHR
is invoked.
Control returns to the shader that executed OpTraceRayKHR
once this
shader returns.
This shader is skipped if the miss shader identified is
VK_SHADER_UNUSED_KHR
.
If the ray was traced with OpRayQueryProceedKHR
, control is returned to
the shader which executed OpRayQueryProceedKHR
, returning false
.
If a closest hit was identified by Ray Closest Hit Determination, the
ray query will now have a committed intersection type of
RayQueryCommittedIntersectionGeneratedKHR
or
RayQueryCommittedIntersectionTriangleKHR
.
If no closest hit was identified, the committed intersection type will be
RayQueryCommittedIntersectionNoneKHR
.
No further processing of a ray query occurs after this result is determined.