Instance Masks in DirectX Raytracing
This article provides an overview of instance masks in DirectX Raytracing (DXR), explaining their architecture and role in ray traversal. It covers how instance masks are defined within acceleration structures, the mathematical bitwise logic used to evaluate them during ray dispatch, and how developers leverage them to cull unnecessary ray-primitive intersection tests directly in hardware to maximize rendering performance.
What Are Instance Masks?
In DirectX Raytracing, scene geometry is organized into a two-level hierarchy of acceleration structures: Bottom-Level Acceleration Structures (BLAS), which hold actual mesh geometry (triangles or procedural primitives), and Top-Level Acceleration Structures (TLAS), which contain instances of these BLAS along with transform matrices and rendering metadata.
An instance mask is an 8-bit integer (ranging from 0x00
to 0xFF) assigned to each instance inside the TLAS via the
D3D12_RAYTRACING_INSTANCE_DESC structure:
typedef struct D3D12_RAYTRACING_INSTANCE_DESC {
...
UINT InstanceMask : 8;
...
} D3D12_RAYTRACING_INSTANCE_DESC;This 8-bit value acts as an identifier or category tag for each instance in the scene, categorizing objects into user-defined groups such as opaque geometry, transparent surfaces, shadow casters, or view-dependent assets.
Filtering Ray-Primitive Intersections
Instance masks filter ray-primitive intersections by determining whether a ray can enter a particular BLAS during the TLAS traversal phase. This filtering is resolved early in hardware, well before any triangle intersection tests or Any-Hit shader evaluations occur.
The Bitwise Mask Test
When launching a ray in HLSL via the TraceRay()
intrinsic function, the developer specifies an 8-bit inclusion mask
(InstanceInclusionMask) alongside ray flags, origins, and
directions:
TraceRay(
AccelerationStructure,
RayFlags,
InstanceInclusionMask, // 8-bit mask passed to the ray
RayContributionToHitGroupIndex,
MultiplierForGeometryContributionToHitGroupIndex,
MissShaderIndex,
Ray,
Payload
);
During TLAS traversal, the GPU performs a bitwise AND operation
between the ray's InstanceInclusionMask and the target
instance’s InstanceMask:
\[\text{Test} = (\text{RayInclusionMask} \ \& \ \text{InstanceMask}) \neq 0\]
- Non-Zero Result: If the result of the bitwise AND operation is greater than zero, the test passes. The ray continues its traversal into the child BLAS associated with that instance to test for bounding volume and primitive intersections.
- Zero Result: If the result is zero, the test fails. The GPU completely ignores the instance. The entire BLAS attached to that instance is culled from the ray's traversal path.
Why Instance Masks Are Essential
Hardware-Level Early Out
Because instance mask evaluation takes place at the TLAS level, instances that fail the mask test incur zero primitive intersection costs. The hardware bypasses all BVH node traversals, triangle tests, Any-Hit shaders, and Closest-Hit shaders that would have otherwise executed for that instance.
Specialized Ray Pipelines
By allocating different bits of the 8-bit mask to different categories, developers can finely tune ray behavior for specific rendering passes:
- Shadow Rays: A shadow ray can use a mask that only tests against shadow-casting geometry, skipping non-shadow-casting particles or decals entirely.
- Reflection Rays: Rough reflections can omit fine-detail geometry like foliage or wireframes to save traversal time.
- First-Person Assets: Player character models can be masked out from camera rays to avoid self-clipping while remaining visible to shadow rays cast by external lights.
- Layered Visibility: Transparent geometry can be isolated from opaque visibility sweeps, preventing costly Any-Hit shader invocations during primary visibility checks.