DirectX Raytracing

DXR (SM 6.3, DXR 1.0; SM 6.5, DXR 1.1) adds hardware ray tracing.

DXR (SM 6.3, DXR 1.0; SM 6.5, DXR 1.1) adds hardware ray tracing. The scene is stored in acceleration structures: bottom-level (BLAS: triangles or AABBs) and top-level (TLAS: instances of BLASes with transforms).

32.1 Shader types

once per DispatchRays thread create primary rays, call TraceRay, write output nearest accepted hit shading, spawn secondary rays every candidate hit on non-opaque geometry alpha testing (IgnoreHit()), early out (AcceptHitAndEndSearch()) sky color, "not in shadow" ray enters a procedural AABB custom geometry; ReportHit(t, kind, attribs) CallShader(index, params) indirect function calls (material system)

All compiled together into a library (-T lib_6_3 or higher) and assembled into a state object (RTPSO) with a shader binding table (SBT) mapping geometry to hit groups.

32.2 A complete ray-traced shadow + shading library

Key system values: DispatchRaysIndex, DispatchRaysDimensions, WorldRayOrigin, WorldRayDirection, ObjectRayOrigin, ObjectRayDirection, RayTMin, RayTCurrent, RayFlags, InstanceIndex, InstanceID (user value), GeometryIndex (DXR 1.1), PrimitiveIndex, HitKind, ObjectToWorld3x4/4x3, WorldToObject3x4/4x3. Recursion depth is set in the pipeline config (MaxTraceRecursionDepth); keep payloads small.

RaytracingAccelerationStructure gScene  : register(t0);
RWTexture2D<float4>             gOutput : register(u0);
StructuredBuffer<float3>        gNormals : register(t1);   // per-vertex normals (example layout)
StructuredBuffer<uint3>         gIndices : register(t2);

cbuffer RTCB : register(b0)
{
    float4x4 gInvViewProj;
    float3   gCamPosRT;
    float    pad0;
    float3   gSunDir;      // direction toward the sun, normalized
    float    pad1;
};

struct RadiancePayload { float3 color; uint depth; };
struct ShadowPayload   { bool hit; };

[shader("raygeneration")]
void RayGen()
{
    uint2 pixel = DispatchRaysIndex().xy;
    float2 dims = DispatchRaysDimensions().xy;
    float2 ndc = (pixel + 0.5) / dims * float2(2, -2) + float2(-1, 1);
    float4 world = mul(gInvViewProj, float4(ndc, 1, 1));

    RayDesc ray;
    ray.Origin    = gCamPosRT;
    ray.Direction = normalize(world.xyz / world.w - gCamPosRT);
    ray.TMin      = 0.001;
    ray.TMax      = 10000.0;

    RadiancePayload payload = { float3(0, 0, 0), 0 };
    TraceRay(gScene, RAY_FLAG_NONE, 0xFF,
             0,    // RayContributionToHitGroupIndex (ray type 0 = radiance)
             2,    // MultiplierForGeometryCont
…

32.3 Intersection shader (procedural sphere)

struct SphereAttr { float3 normal; };

[shader("intersection")]
void SphereIntersection()
{
    float3 o = ObjectRayOrigin(), d = ObjectRayDirection();   // unit sphere at the AABB center
    float b = dot(o, d), c = dot(o, o) - 1.0, a = dot(d, d);
    float disc = b * b - a * c;
    if (disc >= 0)
    {
        float t = (-b - sqrt(disc)) / a;
        if (t >= RayTMin() && t <= RayTCurrent())
        {
            SphereAttr attr; attr.normal = normalize(o + t * d);
            ReportHit(t, 0, attr);                            // hitKind 0 (user-defined)
        }
    }
}

32.4 Inline ray tracing: RayQuery (DXR 1.1, SM 6.5)

RayQuery lets any shader stage (pixel, compute...) trace rays without a state object or SBT — ideal for shadows, AO, and simple queries.

For non-opaque geometry, loop while (q.Proceed()), inspect q.CandidateType(), test alpha using q.CandidatePrimitiveIndex() / q.CandidateTriangleBarycentrics(), and call q.CommitNonOpaqueTriangleHit().

RaytracingAccelerationStructure gTLAS : register(t20);

float TraceShadowInline(float3 origin, float3 dirToLight, float maxDist)
{
    RayQuery<RAY_FLAG_CULL_NON_OPAQUE |
             RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
             RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> q;

    RayDesc ray;
    ray.Origin = origin; ray.Direction = dirToLight; ray.TMin = 0.001; ray.TMax = maxDist;
    q.TraceRayInline(gTLAS, RAY_FLAG_NONE, 0xFF, ray);
    q.Proceed();            // with the flags above, no candidates need manual handling
    return q.CommittedStatus() == COMMITTED_TRIANGLE_HIT ? 0.0 : 1.0;
}

32.5 Newer ray tracing features

SM 6.9 Shader Execution Reordering (SER): dx::HitObject separates traversal from shading; dx::MaybeReorderThread(hitObject) lets hardware regroup threads by hit shader/material for coherence before dx::HitObject::Invoke.

Opacity micromaps (OMM): accelerate alpha-tested geometry by encoding opacity per micro-triangle.

Payload access qualifiers (SM 6.6+, [raypayload] with read(...)/write(...) annotations) help the compiler optimize payload storage.

Check feature support (D3D12_FEATURE_DATA_D3D12_OPTIONS5.RaytracingTier, and newer option structs) before use.