Integrating the algorithms provided by the RTXGI SDK can be accomplished without substantial modifications to an existing renderer, provided the renderer already includes support for GPU ray tracing with a modern API (DirectX Raytracing and/or Vulkan Ray Tracing).
Due to the design of modern ray tracing APIs and the variability of material shaders from one application to another, the RTXGI SDK expects the application to own and maintain ray tracing acceleration structures, shader tables, and ray tracing pipeline state objects. It would be inappropriate for the SDK to own these structures, since this would impose unnecessary limitations on the application and reduce the generality of the SDKs implementations.
The implementation of the DDGI algorithm revolves around a defined volume of space that supports irradiance queries at arbitrary world-space locations. We refer to this space as a DDGIVolume
. Shown below, each DDGIVolume
contains a regular grid of probes that cache irradiance and distance information for use when gathering indirect light in screen-space.
An implementation of DDGI using the RTXGI SDK needs to perform the following steps:
At Load-Time
- Compile the SDK's DDGI shaders with the DirectX Shader Compiler (DXC)
- Describe the properties of one or more
DDGIVolume
- Describe the resources of one or more
DDGIVolume
- Create the DDGIVolume(s)
At Render-Time
- Update and Upload Constants for each relevant, active
DDGIVolume
- Tip: you can manage this manually or with the SDK's
UploadDDGIVolumeConstants()
andUploadDDGIVolumeResourceIndices()
functions
- Tip: you can manage this manually or with the SDK's
- Trace Probe Rays for each relevant, active
DDGIVolume
- Tip: get the ray dispatch dimensions using the SDK's
GetRayDispatchDimensions()
function
- Tip: get the ray dispatch dimensions using the SDK's
- Update Probes using the ray traced probe data for each relevant, active
DDGIVolume
- Tip: use the SDK's
UpdateDDGIVolumeProbes()
function
- Tip: use the SDK's
- Relocate Probes (optional) within relevant, active
DDGIVolume
s to find optimal world-space probe positions for gathering radiance- Tip: use the SDK's
RelocateDDGIVolumeProbes()
function
- Tip: use the SDK's
- Classify Probes (optional) within relevant, active
DDGIVolume
s to deactivate tracing and blending operations for probes that do not contribute to the final result- Tip: use the SDK's
ClassifyDDGIVolumeProbes()
function
- Tip: use the SDK's
- Calculate Variability (optional) within relevant, active
DDGIVolume
s to generate variability measurements for the current update, then use these values to determine if the volume should remain active or not- Tip: use the SDK's
CalculateDDGIVolumeVariability()
andReadbackDDGIVolumeVariability()
functions
- Tip: use the SDK's
- Query Irradiance from relevant, active
DDGIVolume
s to gather indirect lighting in screen-space
The SDK provides host-side and shader-side code that implements most of the steps above. SDK host-side code provides a DDGIVolume
class and rtxgi
namespace functions that support both the DirectX Raytracing and Vulkan Ray Tracing APIs. API-agnostic DDGIVolume
functionality is implemented in the abstract rtxgi::DDGIVolumeBase
class and is provided by the DDGIVolume.h include file and the DDGIVolume.cpp source file.
API-specific code is organized in namespaces. D3D12 functionality is in the rtxgi::d3d12
namespace and is provided by the DDGIVolume_D3D12.h include file and the DDGIVolume_D3D12.cpp source file. Similarly, Vulkan functionality is in the rtxgi::vk
namespace and is provided by the DDGIVolume_VK.h include file and the DDGIVolume_VK.cpp source file.
You only need to include the platform-specific DDGIVolume_[D3D12|VK].h
header file to use the DDGIVolume
.
See the DDGIVolume Reference for more information on creating and using the DDGIVolume
.
The integration steps described above are illustrated in the diagram below, where green bubbles indicate steps handled by the SDK and yellow bubbles indicate steps performed by the application. The API function calls show below are the Direct3D 12 version; however, the Vulkan equivalents of these calls are very similar.
The probe ray tracing step gathers radiance and distance data from the environment surrounding probes contained within a DDGIVolume
. The application is responsible for creating and maintaining the ray tracing acceleration structures and shader tables that specify the scene's geometry and materials.
Probe rays are dispatched by the application using ray generation shaders. A probe ray generation shader should execute the following steps:
- Load the constants of a
DDGIVolume
- Load the probe's state (if probe classification is enabled)
- Compute the probe's world-space position
- Compute the probe ray direction
- Trace the ray
- Handle ray miss and backface hits
- Perform direct lighting for frontface hits
- Sample irradiance from probes near the ray hit location (recursive irradiance)
- Store the final radiance result in the Probe Ray Data texture
The SDK provides several shader functions to help with these steps. See the Shader API for more information. The Test Harness provides an example ray generation shader that demonstrates the above steps in ProbeTraceRGS.hlsl.
Important Note: make sure the transform matrices of ray tracing geometry instances are packed in the proper row-major or column-major format. See Descriptors.hlsl in the Test Harness for an example.
To query irriadiance and gather indirect light in screen-space using a DDGIVolume
, call the DDGIGetVolumeIrradiance(...)
function in a fullscreen compute or pixel shader. This function computes irradiance at an arbitrary world-space point by using the DDGIVolume
to gather and filter the irradiance stored in probes while also eliminating contributions from occluded probes based on the probe distance data.
Provide the following to DDGIGetVolumeIrradiance()
:
- The world-space position of the surface point being shaded.
- A small surface bias value, computed with the
DDGIGetSurfaceBias(...)
function. - The geometric normal direction of the surface (avoid using the shading normal).
- The
DDGIVolumeDescGPU
constants. - The
DDGIVolumeResources
, including the probe irradiance and distance atlas SRVs, probe data SRV, and a bilinear texture sampler.
Examples are provided in IndirectCS.hlsl and ProbeTraceRGS.hlsl. See the Shader API for more information.
The SDK provides the DDGIGetVolumeBlendWeight(...)
shader function to aid in blending between multiple volumes and/or regions not covered by a DDGIVolume
. This use case may arise when a scene has multiple overlapping volumes or if there is a region of the scene that needs indirect lighting and others that strictly do not (for example, due to artistic or performance reasons).
DDGIGetVolumeBlendWeight()
computes a weight value in the range [0, 1] for a world position and volume pair. All positions inside the given volume recieve a weight of 1 (full contribution) and positions outside the volume receive a weight in [0, 1] that decreases as the position moves further away from the volume. Below is an example of how to use this function when blending between a volume and non-volume region.
// A hard coded ambient term (black) may be passed in
float3 ambient = 0.f;
// Get the volume blend weight (0-1)
float blendWeight = DDGIGetVolumeBlendWeight( worldPosHitT.xyz, DDGIVolume);
// Only get irradiance if it is necessary
if (blendWeight > 0.f)
{
// Get irradiance from the DDGIVolume
irradiance = DDGIGetVolumeIrradiance(
worldPosHitT.xyz,
surfaceBias,
normal,
DDGIVolume,
resources);
}
// Blend between irradiance and the constant ambient term
irradiance = blendWeight * irradiance + (1.f - blendWeight) * ambient;
When blending between multiple volumes, blending only needs to occur at the edges of the volumes. When volumes overlap, sort and select the appropriate volume to use in shading based on heuristics such as probe density, proximity to the surface, the volume's screen coverage, and/or an artist driven priority value. An example of this functionality is available in the RTXGI UE4 Plugin.
The Test Harness sample application provides examples of a full DDGI integration for the D3D12 and Vulkan APIs.
-
DDGI Shader Compilation: see
CompileDDGIVolumeShaders()
in DDGI.cpp. -
API-specific initialization and start-up: see
Initialize()
in DDGI_D3D.cpp and/or DDGI_VK.cpp.
-
Update/Upload Constants: see
Update()
andExecute()
in DDGI_D3D12.cpp and DDGI_VK.cpp. -
Trace Probe Rays: see
RayTraceVolumes()
in DDGI_D3D12.cpp and DDGI_VK.cpp. -
Update/Relocate/Classify Probes: see
Execute()
in DDGI_D3D12.cpp and DDGI_VK.cpp. -
Query Irradiance: see
GatherIndirectLighting()
in DDGI_D3D12.cpp and DDGI_VK.cpp and IndirectCS.hlsl.