FSR™ Ray Regeneration 1.2.0
Figure 1: Sample output from FSR™ Ray Regeneration.
FSR™ Ray Regeneration is a machine learning-based denoiser for ray-traced workloads. It improves visual quality by reducing noise in rendered frames while preserving detail.
Table of contents
- 1. Introduction
- 2. Getting started
- 2.1. Setting up your project
- 2.2. Setting up logging
- 2.3. Querying support
- 2.4. Creating the context
- 2.5. Dispatching
- 2.5.1. Checkerboard reconstruction
- 2.5.2.
ffxDispatchDescDenoiser - 2.5.3.
FfxApiDispatchDenoiserFlags - 2.5.4.
FfxApiDenoiserSignal - 2.5.5.
ffxDispatchDescDenoiserAmbientOcclusion - 2.5.6.
ffxDispatchDescDenoiserDirectDiffuse - 2.5.7.
ffxDispatchDescDenoiserDirectSpecular - 2.5.8.
ffxDispatchDescDenoiserDominantLight - 2.5.9.
ffxDispatchDescDenoiserIndirectDiffuse - 2.5.10.
ffxDispatchDescDenoiserIndirectSpecular - 2.5.11.
ffxDispatchDescDenoiserSpecularOcclusion
- 2.6. Configuring settings
- 2.7. Cleaning up
- 3. Performance
- 4. Debugging
- 5. Best practices
- 6. Requirements
- 7. Version history
- 8. See also
1. Introduction
Since the advent of hardware-accelerated ray tracing, real-time game and rendering engines have increasingly adopted ray tracing techniques. From realistic reflections to finely detailed shadows, ray tracing has significantly elevated visual fidelity in modern games. As GPU ray tracing capabilities continue to improve, developers are pushing the boundaries of global illumination and exploring real-time path tracing. However, raw ray-traced outputs are inherently noisy, making effective denoising essential for producing clean, high-quality images.
Denoising transforms noisy ray- or path-traced outputs into coherent, visually accurate images, often leveraging both spatial and temporal information. FSR™ Ray Regeneration performs this task with a key advantage: it uses machine learning to dynamically determine optimal filter weights, delivering superior results compared to purely analytical methods.
1.1. Decoupled denoising vs. joint denoising
FSR™ Ray Regeneration performs denoising independently of upscaling, making it a decoupled denoiser. In contrast, denoising and upscaling can also be combined into a single, joint operation. Both approaches are valid, but decoupling denoising into its own dispatch call simplifies adding additional rendered content afterward.
Although upscaling is not strictly required for denoising, rendering expensive ray-traced effects, especially path tracing, at native resolution can be very demanding on hardware. With significant advancements in upscaling technology, incorporating upscaling into the rendering pipeline is strongly recommended. Additionally, the temporal anti-aliasing provided by upscalers such as FSR™ 4 adds an extra layer of smoothing when used alongside FSR™ Ray Regeneration. For optimal visual results, FSR™ Ray Regeneration should be paired with FSR™ 4.
1.2. Signals
To maximize compatibility and efficiency when denoising your game’s specific workloads, FSR™ Ray Regeneration provides multiple input/output signals:
| Signal flags | Input/output signals: |
|---|---|
FFX_DENOISER_SIGNAL_AMBIENT_OCCLUSION | Ambient occlusion (in [0,1]) |
FFX_DENOISER_SIGNAL_DIRECT_DIFFUSE | Direct diffuse |
FFX_DENOISER_SIGNAL_DIRECT_SPECULAR | Direct specular |
FFX_DENOISER_SIGNAL_DOMINANT_LIGHT_VISIBILITY | Dominant light visibility (in [0,1]) |
FFX_DENOISER_SIGNAL_INDIRECT_DIFFUSE | Indirect diffuse |
FFX_DENOISER_SIGNAL_INDIRECT_SPECULAR | Indirect specular |
FFX_DENOISER_SIGNAL_SPECULAR_OCCLUSION | Specular occlusion (in [0,1]) |
The selected signals are specified via the signalFlags member of the ffxCreateContextDescDenoiser context creation description.
2. Getting started
2.1. Setting up your project
FSR™ Ray Regeneration is part of the FSR™ SDK. Before getting started, make sure to read the Getting Started with the FSR™ API guide. Once familiar with the API, follow these steps to prepare your project for FSR™ Ray Regeneration:
- Add the FSR™ API include headers to your project’s include directories.
- Add the FSR™ Ray Regeneration headers to your project’s include directories.
- Link your project against
amd_fidelityfx_loader_dx12.lib, located in FidelityFX/signedbin. - Copy
amd_fidelityfx_loader_dx12.dllandamd_fidelityfx_denoiser_dx12.dllfrom FidelityFX/signedbin into your project’s executable directory.
2.2. Setting up logging
By default, all messages (FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_VERBOSE) are output as debug strings.
Logging can be explicitly setup before (or after) context creation for the denoiser effect by passing a ffxConfigureDescGlobalDebug configure description to ffxConfigure.
// Example: configuring the logging callback for the denoiser effect.ffx::ConfigureDescGlobalDebug configureDesc = {};configureDesc.effectId = FFX_API_EFFECT_ID_DENOISER;// If set to nullptr, messages will be output as debug strings.configureDesc.fpMessage = [](../uint32_t type, const wchar_t* message/){ switch (type) {
case FFX_API_MESSAGE_TYPE_ERROR: { LogError(message); break; } case FFX_API_MESSAGE_TYPE_WARNING: { LogWarning(message); break; } default: { break; }
}};configureDesc.debugLevel = FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_VERBOSE;
ffx::ReturnCode result = ffx::Configure(configureDesc);assert(result == ffx::ReturnCode::Ok);2.3. Querying support
Before context creation, you can query supported versions by passing a ffxQueryDescGetVersions query description to ffxQuery.
If the query returns no contexts, support for FSR™ Ray Regeneration is not available.
// Example: querying all supported FSR™ Ray Regeneration versions.uint64_t supportedVersionCount = 0;ffx::QueryDescGetVersions queryDesc = {};queryDesc.createDescType = FFX_API_EFFECT_ID_DENOISER;queryDesc.device = GetDevice()->GetImpl()->DX12Device();queryDesc.outputCount = &supportedVersionCount;ffx::ReturnCode result = ffx::Query(queryDesc);assert(result == ffx::ReturnCode::Ok);
m_DenoiserVersionIds.resize(supportedVersionCount);m_DenoiserVersionStrings.resize(supportedVersionCount);
queryDesc.versionIds = m_DenoiserVersionIds.data();queryDesc.versionNames = m_DenoiserVersionStrings.data();result = ffx::Query(queryDesc);assert(result == ffx::ReturnCode::Ok);
m_DenoiserAvailable = not versionIds.empty();2.4. Creating the context
To start using FSR™ Ray Regeneration, you need to create a denoiser context by passing a ffxCreateContextDescDenoiser context creation description along with a backend description to ffxCreateContext.
The parameters you provide determine the internal resource allocations and pipeline state compilations.
Creating contexts in time-critical paths is not recommended due to their initialization cost.
If the hardware does not support FSR™ Ray Regeneration, ffxCreateContext will return an error and the context pointer will remain unset.
// Example: creating a denoiser context with the desired signal flags.ffx::CreateBackendDX12Desc backendDesc = {};backendDesc.device = GetDevice()->GetImpl()->DX12Device();
ffx::CreateContextDescDenoiser createDesc = {};createDesc.version = FFX_DENOISER_VERSION;createDesc.maxRenderSize = { resInfo.UpscaleWidth, resInfo.UpscaleHeight };// SignalscreateDesc.signalFlags = FFX_DENOISER_SIGNAL_NONE;if (m_EnableDirectDiffuse){ // Flag indicating that direct diffuse needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_DIRECT_DIFFUSE;}if (m_EnableDirectSpecular){ // Flag indicating that direct specular needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_DIRECT_SPECULAR;}if (m_EnableIndirectDiffuse){ // Flag indicating that indirect diffuse needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_INDIRECT_DIFFUSE;}if (m_EnableIndirectSpecular){ // Flag indicating that indirect specular needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_INDIRECT_SPECULAR;}if (m_EnableDominantLightVisibility){ // Flag indicating that dominant light visibility needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_DOMINANT_LIGHT_VISIBILITY;}if (m_EnableAmbientOcclusion){ // Flag indicating that ambient occlusion needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_AMBIENT_OCCLUSION;}if (m_EnableSpecularOcclusion){ // Flag indicating that specular occlusion needs to be denoised. denoiserContextDesc.signalFlags |= FFX_DENOISER_SIGNAL_SPECULAR_OCCLUSION;}// Checkerboard reconstruction (optional, must be a subset of signalFlags)createDesc.checkerboardSignalFlags = FFX_DENOISER_SIGNAL_NONE;// FlagsdenoiserContextDesc.flags = {};if (m_EnableDebugging){ // Flag indicating that debug features may be enabled. Memory usage may increase. denoiserContextDesc.flags |= FFX_DENOISER_ENABLE_DEBUGGING;}if (m_EnableValidation){ // Flag indicating that exhaustive validation should be enabled. Performance may decrease. denoiserContextDesc.flags |= FFX_DENOISER_ENABLE_VALIDATION;}
// Create the denoiser contextffx::ReturnCode result = ffx::CreateContext(m_pDenoiserContext, nullptr, createDesc, backendDesc);assert(result == ffx::ReturnCode::Ok);2.4.1. ffxCreateContextDescDenoiser
| Parameter | Description |
|---|---|
version | The version of the API the application was built against. Must be set to FFX_DENOISER_VERSION. |
maxRenderSize | Maximum size that rendering will be performed at. Determines internal resource allocation sizes. |
signalFlags | Signal flags corresponding to a combination of values from FfxApiDenoiserSignalFlags. Specifies which signals will be denoised. |
checkerboardSignalFlags | Signal flags corresponding to a combination of values from FfxApiDenoiserSignalFlags for signals that use checkerboard reconstruction. Must be a subset of signalFlags. |
flags | Zero or a combination of values from FfxApiCreateContextDenoiserFlags. |
2.4.2. FfxApiCreateContextDenoiserFlags
| Flag | Description |
|---|---|
FFX_DENOISER_ENABLE_DEBUGGING | Enables debug features. Memory usage may increase. Required to dispatch ffxDispatchDescDenoiserDebugView. |
FFX_DENOISER_ENABLE_VALIDATION | Enables exhaustive input validation. Performance may decrease. |
For use cases that require a specific version, you can override the implicit default version by passing a ffxOverrideVersion description to ffxCreateContext too.
// Example: creating a denoiser context pinned to a specific version.ffx::CreateContextDescOverrideVersion versionOverride = {};versionOverride.versionId = m_DenoiserVersionIds[m_SelectedDenoiserVersion];
// Create the denoiser contextffx::ReturnCode result = ffx::CreateContext(m_pDenoiserContext, nullptr, createDesc, backendDesc, versionOverride);assert(result == ffx::ReturnCode::Ok);2.5. Dispatching
Denoising is performed on the GPU by passing the below dispatch descriptions to ffxDispatch.
Dispatch descriptions can be passed if and only if the corresponding dispatch conditions are met by the context.
Furthermore, the majority of dispatch descriptions are non-optional and must be passed if and only if the corresponding dispatch conditions are met by the context.
| Dispatch Description | Dispatch Condition | Optional |
|---|---|---|
ffxDispatchDescDenoiser | / | No |
ffxDispatchDescDenoiserAmbientOcclusion | FFX_DENOISER_SIGNAL_AMBIENT_OCCLUSION must be set | No |
ffxDispatchDescDenoiserDebugView | FFX_DENOISER_ENABLE_DEBUGGING must be set | Yes |
ffxDispatchDescDenoiserDirectDiffuse | FFX_DENOISER_SIGNAL_DIRECT_DIFFUSE must be set | No |
ffxDispatchDescDenoiserDirectSpecular | FFX_DENOISER_SIGNAL_DIRECT_SPECULAR must be set | No |
ffxDispatchDescDenoiserDominantLight | FFX_DENOISER_SIGNAL_DOMINANT_LIGHT_VISIBILITY must be set | No |
ffxDispatchDescDenoiserIndirectDiffuse | FFX_DENOISER_SIGNAL_INDIRECT_DIFFUSE must be set | No |
ffxDispatchDescDenoiserIndirectSpecular | FFX_DENOISER_SIGNAL_INDIRECT_SPECULAR must be set | No |
ffxDispatchDescDenoiserSpecularOcclusion | FFX_DENOISER_SIGNAL_SPECULAR_OCCLUSION must be set | No |
FSR™ Ray Regeneration uses a linked-list pattern to pass multiple dispatch descriptions to a single ffxDispatch call.
Each description header contains a pNext pointer that chains the next description in sequence.
The ffxDispatchDescDenoiser description is always the head of the chain; all signal and debug-view descriptions are linked after it.
All descriptions passed to a single ffxDispatch call must remain alive (i.e., not go out of scope) for the duration of that call.
// Example: dispatching all active signals using manual pNext chaining.// Needs to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiser dispatchDesc = {};// ... assign description members ...
ffxDispatchDescHeader* prevHeader = &dispatchDesc.header;const auto link = [&prevHeader](../auto& desc/){ ffxDispatchDescHeader* const nextHeader = &desc.header; prevHeader->pNext = nextHeader; prevHeader = nextHeader;};
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserAmbientOcclusion dispatchDescAmbientOcclusion = {};if (m_EnableAmbientOcclusion){ // ... assign description members ...
link(dispatchDescAmbientOcclusion);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserDirectDiffuse dispatchDescDirectDiffuse = {};if (m_EnableDirectDiffuse){ // ... assign description members ...
link(dispatchDescDirectDiffuse);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserDirectSpecular dispatchDescDirectSpecular = {};if (m_EnableDirectSpecular){ // ... assign description members ...
link(dispatchDescDirectSpecular);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserDominantLight dispatchDescDominantLight = {};if (m_EnableDominantLightVisibility){ // ... assign description members ...
link(dispatchDescDominantLight);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserIndirectDiffuse dispatchDescIndirectDiffuse = {};if (m_EnableIndirectDiffuse){ // ... assign description members ...
link(dispatchDescIndirectDiffuse);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserIndirectSpecular dispatchDescIndirectSpecular = {};if (m_EnableIndirectSpecular){ // ... assign description members ...
link(dispatchDescIndirectSpecular);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserSpecularOcclusion dispatchDescSpecularOcclusion = {};if (m_EnableSpecularOcclusion){ // ... assign description members ...
link(dispatchDescSpecularOcclusion);}
// Need to persist in the ::ffxDispatch scope.ffx::DispatchDescDenoiserDebugView dispatchDescDebugView = {};if (m_EnableDebugging && m_ShowDebugView){ // ... assign description members ...
link(dispatchDescDebugView);}
// ffx::Dispatch cannot be used because it will reset pNext.ffxReturnCode_t result = ::ffxDispatch(&m_pDenoiserContext, &dispatchDesc.header);assert(result == FFX_API_RETURN_OK);Alternatively, the templated ffx_api.hpp allows linking multiple inputs together as variable arguments.
// Example: dispatching indirect diffuse and specular signals using the variadic ffx::Dispatch helper.// Denoise indirect diffuse and specular
ffx::DispatchDescDenoiser dispatchDesc = {};// ... assign description members ...
ffx::DispatchDescDenoiserIndirectDiffuse dispatchDescIndirectDiffuse = {};// ... assign description members ...
ffx::DispatchDescDenoiserIndirectSpecular dispatchDescIndirectSpecular = {};// ... assign description members ...
ffx::ReturnCode result = ffx::Dispatch(m_pDenoiserContext, dispatchDesc, DispatchDescDenoiserIndirectDiffuse, DispatchDescDenoiserIndirectSpecular);assert(result == ffx::ReturnCode::Ok);2.5.1. Checkerboard reconstruction
To reduce ray tracing cost, signals can be rendered at half horizontal resolution by tracing alternate pixels each frame in a checkerboard pattern. FSR™ Ray Regeneration can reconstruct a full-resolution signal from these half-resolution inputs using depth- and normal-aware bilateral filtering.
To enable checkerboard reconstruction for a signal, include its flag in both signalFlags and checkerboardSignalFlags at context creation.
checkerboardSignalFlags must always be a subset of signalFlags.
In the checkerboard pattern, only half the pixels are traced per frame, alternating as follows:
// Checkerboard pattern: 0 = inactive (not traced), 1 = active (traced). x=0 x=1 x=2 x=3y=0: 0 1 0 1y=1: 1 0 1 0y=2: 0 1 0 1Where 0 indicates an inactive pixel (not traced this frame) and 1 indicates an active pixel (traced this frame).
The origin of the pattern alternates each frame via checkerboardOrigin in the per-signal FfxApiDenoiserSignal:
checkerboardOrigin = 0: pixel(0,0)is active (traced).checkerboardOrigin = 1: pixel(1,0)is active (traced).
The typical usage is checkerboardOrigin = frameIndex & 1.
Active pixels must be packed into a half-width texture (width = renderSize.width / 2) before being passed as the input of the signal.
FSR™ Ray Regeneration will unpack them and reconstruct the inactive pixels internally.
2.5.2. ffxDispatchDescDenoiser
| Parameter | Description |
|---|---|
commandList | A pointer to the command list for recording. |
linearDepth | Resource containing signed linear depth values for the current frame. Channels: R: signed linear depth (CurrentLinearDepth)Preferred format: R32_FLOAT |
motionVectors | Resource containing motion vectors for the current frame. Channels: RG: 2D motion vectors (PreviousUV - CurrentUV)B: signed linear depth delta (PreviousLinearDepth - CurrentLinearDepth)Preferred format: RGBA16_FLOAT |
normals | Resource containing normals, roughness, and material type for the current frame. Channels: RG: octahedrally encoded normalsB: linear roughnessA: material type (see docs for more info)Preferred format: RGB10A2_UNORM |
specularAlbedo | Resource containing specular albedo for the current frame. If FFX_DENOISER_DISPATCH_NON_GAMMA_ALBEDO is not added to flags, all channels are expected to use sqrt encoding.Channels: RGB: specular albedo (sqrt(SpecularAlbedo))Can be zero-initialized if and only if FFX_DENOISER_SIGNAL_DIRECT_SPECULAR, FFX_DENOISER_SIGNAL_INDIRECT_SPECULAR, and FFX_DENOISER_SIGNAL_DOMINANT_LIGHT_VISIBILITY are not set in the context creation signal flags.Preferred format: RGBA8_UNORM |
diffuseAlbedo | Resource containing diffuse albedo for the current frame. If FFX_DENOISER_DISPATCH_NON_GAMMA_ALBEDO is not added to flags, all channels are expected to use sqrt encoding.Channels: RGB: diffuse albedo (e.g., BaseColor * (1 - Metalness)) (sqrt(DiffuseAlbedo))Can be zero-initialized if and only if FFX_DENOISER_SIGNAL_DIRECT_DIFFUSE, FFX_DENOISER_SIGNAL_INDIRECT_DIFFUSE, and FFX_DENOISER_SIGNAL_DOMINANT_LIGHT_VISIBILITY are not set in the context creation signal flags.Preferred format: RGBA8_UNORM |
motionVectorScale | Scale factor for transforming motion vectors into UV/depth space. Channels: RG: scale factor for transforming 2D motion vectors into UV space.For motion vectors computed as PreviousUV - CurrentUV, use { .x = +1.0f, .y = +1.0f }.For motion vectors computed as PreviousNDC - CurrentNDC, use { .x = +0.5f, .y = -0.5f }.B: scale factor for transforming signed linear depth delta.For depth deltas computed as PreviousLinearDepth - CurrentLinearDepth, use { .z = +1.0f }. |
jitterOffsets | Subpixel jitter offsets applied to the camera projection, expressed in screen pixels. |
cameraPositionDelta | Camera movement since last frame (PreviousPosition - CurrentPosition), expressed in world space. |
view | World-to-view transformation matrix for the current frame. Matrix convention: Storage: row-major (rows stored contiguously in memory)Multiplication: row vectors (v' = vM)Compatibility: - Column-major with column vectors (e.g., OpenGL, Cauldron): direct copy ( memcpy), no transpose needed- Column-major with row vectors: requires transpose - Row-major with row vectors (e.g., DirectXMath): direct copy ( memcpy)- Row-major with column vectors: requires transpose |
projection | Unjittered view-to-projection transformation matrix for the current frame. Matrix convention: Storage: row-major (rows stored contiguously in memory)Multiplication: row vectors (v' = vM)Compatibility: - Column-major with column vectors (e.g., OpenGL, Cauldron): direct copy ( memcpy), no transpose needed- Column-major with row vectors: requires transpose - Row-major with row vectors (e.g., DirectXMath): direct copy ( memcpy)- Row-major with column vectors: requires transpose |
linearDepthBounds | Absolute linear depth bounds considered for denoising. Passthrough is enabled for signal texels where the corresponding absolute linear depth values are outside [linearDepthBounds.min, linearDepthBounds.max]. |
renderSize | Resolution used for rendering the current frame input resources. |
frameIndex | Index of the current frame. |
flags | Zero or a combination of values from FfxApiDispatchDenoiserFlags. |
2.5.3. FfxApiDispatchDenoiserFlags
| Flag | Description |
|---|---|
FFX_DENOISER_DISPATCH_RESET | Resets the history accumulation. Use when the camera cuts or the scene changes discontinuously. |
FFX_DENOISER_DISPATCH_NON_GAMMA_ALBEDO | Indicates that the specularAlbedo and diffuseAlbedo resources are in linear space rather than sqrt-encoded. |
Depth values and depth deltas are computed using signed linear depth.
- Signed means the depth value is dependent of whether the camera is facing forward or backward in view space.
- Linear means the depth is expressed in view space (z component), rather than NDC space.
2.5.4. FfxApiDenoiserSignal
Each per-signal dispatch description holds a signal member of type FfxApiDenoiserSignal, which carries the input resource, the output resource, and the checkerboard origin for that signal.
| Parameter | Description |
|---|---|
input | Input resource containing the noisy signal to denoise. |
output | Output resource that will receive the denoised signal. May alias input if in-place denoising is desired. |
checkerboardOrigin | The X-coordinate of the first traced pixel at Y=0 in the checkerboard pattern. 0 means pixel (0,0) was traced; 1 means pixel (1,0) was traced. Typically set to frameIndex & 1.Must be zero-initialized if this signal is not set in checkerboardSignalFlags. Only meaningful if this signal is set in checkerboardSignalFlags. |
2.5.5. ffxDispatchDescDenoiserAmbientOcclusion
| Parameter | Description |
|---|---|
signal | Ambient occlusion signal to denoise. Channels: R:input: ambient occlusion in [0,1], where 0 is fully occluded and 1 is fully exposed.output: denoised ambient occlusion in [0,1] (or input if passthrough).Preferred format: R8_UNORM |
2.5.6. ffxDispatchDescDenoiserDirectDiffuse
| Parameter | Description |
|---|---|
signal | Direct diffuse radiance signal to denoise. Channels: RGB:input: direct diffuse radiance to denoise.output: denoised direct diffuse radiance (or input if passthrough).A:input: undefined non-negative value (must be valid if the signal is active; otherwise negative).output: preserved (or input if passthrough).Preferred format: RGBA16_FLOAT |
2.5.7. ffxDispatchDescDenoiserDirectSpecular
| Parameter | Description |
|---|---|
signal | Direct specular radiance signal to denoise. Channels: RGB:input: direct specular radiance to denoise.output: denoised direct specular radiance (or input if passthrough).A:input: undefined non-negative value (must be valid if the signal is active; otherwise negative).output: preserved (or input if passthrough).Preferred format: RGBA16_FLOAT |
2.5.8. ffxDispatchDescDenoiserDominantLight
| Parameter | Description |
|---|---|
signal | Dominant light visibility signal to denoise. Channels: R:input: dominant light visibility as ray hit distance in [0, FP16_MAX], where FP16_MAX is fully exposed.output: denoised dominant light visibility in [0,1] (or input if passthrough).Preferred format: R16_FLOAT (input) / R8_UNORM (output) |
direction | Dominant light direction, expressed from light source to target. |
emission | Dominant light emission (LightColor * LightIntensity). |
angularRadius | Dominant light angular radius, expressed in radians. |
2.5.9. ffxDispatchDescDenoiserIndirectDiffuse
| Parameter | Description |
|---|---|
signal | Indirect diffuse radiance signal to denoise. Channels: RGB:input: indirect diffuse radiance to denoise.output: denoised indirect diffuse radiance (or input if passthrough).A:input: indirect diffuse ray hit distance (must be valid if the signal is active; otherwise negative).output: preserved (or input if passthrough).Preferred format: RGBA16_FLOAT |
2.5.10. ffxDispatchDescDenoiserIndirectSpecular
| Parameter | Description |
|---|---|
signal | Indirect specular radiance signal to denoise. Channels: RGB:input: indirect specular radiance to denoise.output: denoised indirect specular radiance (or input if passthrough).A:input: indirect specular ray hit distance (must be valid if the signal is active; otherwise negative).output: preserved (or input if passthrough).Preferred format: RGBA16_FLOAT |
2.5.11. ffxDispatchDescDenoiserSpecularOcclusion
| Parameter | Description |
|---|---|
signal | Specular occlusion signal to denoise. Channels: R:input: specular occlusion in [0,1], where 0 is fully occluded and 1 is fully exposed.output: denoised specular occlusion in [0,1] (or input if passthrough).Preferred format: R8_UNORM |
2.6. Configuring settings
To achieve the best results with FSR™ Ray Regeneration, some settings may need to be adjusted.
The default values are already set to sensible presets and are not simply zeros.
A recommended best practice when modifying settings is to first query the current defaults by passing a ffxQueryDescDenoiserGetDefaultKeyValue to ffxQuery.
This ensures that you start from a valid baseline.
Example code for querying the default value of the stability bias setting:
// Example: querying the default value of FFX_API_CONFIGURE_DENOISER_KEY_STABILITY_BIAS.float stabilityBias;
ffx::QueryDescDenoiserGetDefaultKeyValue queryDesc = {};queryDesc.key = FFX_API_CONFIGURE_DENOISER_KEY_STABILITY_BIAS;queryDesc.count = 1u;queryDesc.data = &stabilityBias;
ffx::ReturnCode result = ffx::Query(m_pDenoiserContext, queryDesc);assert(result == ffx::ReturnCode::Ok);New denoiser settings can be committed at any time before calling ffxDispatch and do not need to be updated every frame.
To apply the settings, pass a ffxConfigureDescDenoiserKeyValue to ffxConfigure.
2.6.1. ffxConfigureDescDenoiserKeyValue
| Parameter | Description |
|---|---|
key | Configuration key corresponding to an entry of FfxApiConfigureDenoiserKey. |
count | Number of elements to configure. For scalar settings this is 1. |
data | Pointer to an array of count configuration values. The element type is determined by the chosen key. |
2.6.2. ffxQueryDescDenoiserGetDefaultKeyValue
| Parameter | Description |
|---|---|
key | Configuration key corresponding to an entry of FfxApiConfigureDenoiserKey. |
count | Number of elements to query. For scalar settings this is 1. |
data | Pointer to an array of count elements that will receive the default values. The element type is determined by the chosen key. |
Example code for configuring the stability bias setting with a custom value:
// Example: applying a custom value for FFX_API_CONFIGURE_DENOISER_KEY_STABILITY_BIAS.float stabilityBias = ...;
ffx::ConfigureDescDenoiserKeyValue configureDesc = {};configureDesc.key = FFX_API_CONFIGURE_DENOISER_KEY_STABILITY_BIAS;configureDesc.count = 1u;configureDesc.data = &stabilityBias;
ffx::ReturnCode result = ffx::Configure(m_pDenoiserContext, configureDesc);assert(result == ffx::ReturnCode::Ok);2.6.3. FfxApiConfigureDenoiserKey
| Key | Description |
|---|---|
FFX_API_CONFIGURE_DENOISER_KEY_CROSS_BILATERAL_NORMAL_STRENGTH | Override the strength of the cross bilateral normal term. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_STABILITY_BIAS | Override the bias of the temporal accumulation to be more stable but less responsive. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_MAX_RADIANCE | Override the maximum radiance value. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_RADIANCE_CLIP_STD_K | Override the standard deviation K value used for radiance clipping. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_GAUSSIAN_KERNEL_RELAXATION | Override the Gaussian kernel relaxation factor. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_DISOCCLUSION_THRESHOLD | Override the disocclusion threshold used for depth comparisons during temporal reprojection. Format: a single float scalar. |
FFX_API_CONFIGURE_DENOISER_KEY_DEBUG_VIEW_LINEAR_DEPTH_BOUNDS | Override the absolute linear depth bounds used for normalizing the absolute linear depth debug view. Format: a single FfxApiFloatBounds. |
2.7. Cleaning up
The application is responsible for cleaning up any created denoiser context.
This is done by calling ffxDestroyContext with the context to be destroyed.
3. Performance
FSR™ Ray Regeneration performance may vary depending on your target hardware and configuration.
3.1. Timings
3.1.1. Denoising 4 signals + dominant light signal:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 1.13 |
| 1920x1080 | 4.09 |
| 2560x1440 | 7.72 |
3.1.2. Denoising 4 signals:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 1.09 |
| 1920x1080 | 3.93 |
| 2560x1440 | 7.37 |
3.1.3. Denoising 2 signals + dominant light signal:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 0.94 |
| 1920x1080 | 3.33 |
| 2560x1440 | 6.34 |
3.1.4. Denoising 2 signals:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 0.87 |
| 1920x1080 | 3.05 |
| 2560x1440 | 5.84 |
3.1.5. Denoising 1 signal + dominant light signal:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 0.85 |
| 1920x1080 | 2.85 |
| 2560x1440 | 5.51 |
3.1.6. Denoising 1 signal:
| Target Render Resolution | Average [ms] |
|---|---|
| 960x540 | 0.78 |
| 1920x1080 | 2.63 |
| 2560x1440 | 5.18 |
Performance figures are accurate at the time of writing for an AMD Radeon™ RX 9070 XT and are subject to change.
3.2. Memory requirements
FSR™ Ray Regeneration requires additional GPU local memory for use by the GPU. When using the API, this memory is allocated during context creation via the series of callbacks that make up the backend interface. This memory is used to store intermediate surfaces computed by the algorithm, as well as surfaces that persist across multiple frames of the application.
The tables below summarize the memory usage of FSR™ Ray Regeneration under various operating conditions. Here, direct diffuse, direct specular, indirect diffuse, and indirect specular are considered separate signals. Ambient occlusion, dominant light visibility, and specular occlusion are considered one signal. Therefore, up to a total of 5 signals can be denoised.
3.2.1. Denoising 5 signals:
| Render Resolution | Total Working Set [MB] | Persistent Working Set [MB] | Aliasable Working Set [MB] |
|---|---|---|---|
| 960x540 | 111 | 56 | 55 |
| 1920x1080 | 394 | 195 | 199 |
| 2560x1440 | 677 | 349 | 328 |
3.2.2. Denoising 4 signals:
| Render Resolution | Total Working Set [MB] | Persistent Working Set [MB] | Aliasable Working Set [MB] |
|---|---|---|---|
| 960x540 | 102 | 47 | 55 |
| 1920x1080 | 362 | 163 | 199 |
| 2560x1440 | 619 | 291 | 328 |
3.2.3. Denoising 3 signals:
| Render Resolution | Total Working Set [MB] | Persistent Working Set [MB] | Aliasable Working Set [MB] |
|---|---|---|---|
| 960x540 | 94 | 39 | 55 |
| 1920x1080 | 330 | 131 | 199 |
| 2560x1440 | 562 | 234 | 328 |
3.2.4. Denoising 2 signals:
| Render Resolution | Total Working Set [MB] | Persistent Working Set [MB] | Aliasable Working Set [MB] |
|---|---|---|---|
| 960x540 | 85 | 30 | 55 |
| 1920x1080 | 298 | 99 | 199 |
| 2560x1440 | 504 | 176 | 328 |
3.2.5. Denoising 1 signal:
| Render Resolution | Total Working Set [MB] | Persistent Working Set [MB] | Aliasable Working Set [MB] |
|---|---|---|---|
| 960x540 | 76 | 22 | 54 |
| 1920x1080 | 267 | 68 | 199 |
| 2560x1440 | 447 | 119 | 328 |
Memory figures are accurate at the time of writing for an AMD Radeon™ RX 9070 XT and are subject to change.
3.2.6. ffxQueryDescDenoiserGetGPUMemoryUsage
| Parameter | Description |
|---|---|
device | A pointer to the device. For DX12: pointer to ID3D12Device. |
maxRenderSize | Maximum size that rendering will be performed at. Must match the value used (or intended) for context creation. |
signalFlags | Signal flags corresponding to a combination of values from FfxApiDenoiserSignalFlags. Must match the value used (or intended) for context creation. |
checkerboardSignalFlags | Signal flags for checkerboard reconstruction. Must match the value used (or intended) for context creation. |
flags | Create flags. Must match the value used (or intended) for context creation. |
gpuMemoryUsage | Pointer to a FfxApiEffectMemoryUsage structure that will receive the GPU memory usage figures. |
The expected memory usage can be queried before context creation by passing a ffxQueryDescDenoiserGetGPUMemoryUsage to ffxQuery:
// Example: querying the expected GPU memory usage before context creation.FfxApiEffectMemoryUsage memoryUsage = {};ffx::QueryDescDenoiserGetGPUMemoryUsage queryDesc = {};queryDesc.device = GetDevice()->GetImpl()->DX12Device();queryDesc.maxRenderSize = denoiserContextDesc.maxRenderSize;queryDesc.signalFlags = denoiserContextDesc.signalFlags;queryDesc.checkerboardSignalFlags = denoiserContextDesc.checkerboardSignalFlags;queryDesc.flags = denoiserContextDesc.flags;queryDesc.gpuMemoryUsage = &memoryUsage;
ffx::ReturnCode result = ffx::Query(queryDesc, versionOverride);assert(result == ffx::ReturnCode::Ok);
LOG(L"Denoiser GPU Memory Usage totalUsageInBytes %.3f MB aliasableUsageInBytes %.3f MB", memoryUsage.totalUsageInBytes / 1048576.f, memoryUsage.aliasableUsageInBytes / 1048576.f);The actual memory usage can be queried after context creation by passing a ffxQueryDescDenoiserGetGPUMemoryUsage to ffxQuery:
// Example: querying the actual GPU memory usage after context creation.FfxApiEffectMemoryUsage memoryUsage = {};ffx::QueryDescDenoiserGetGPUMemoryUsage queryDesc = {};queryDesc.device = GetDevice()->GetImpl()->DX12Device();queryDesc.maxRenderSize = denoiserContextDesc.maxRenderSize;queryDesc.signalFlags = denoiserContextDesc.signalFlags;queryDesc.checkerboardSignalFlags = denoiserContextDesc.checkerboardSignalFlags;queryDesc.flags = denoiserContextDesc.flags;queryDesc.gpuMemoryUsage = &memoryUsage;
ffx::ReturnCode result = ffx::Query(m_pDenoiserContext, queryDesc);assert(result == ffx::ReturnCode::Ok);
LOG(L"Denoiser GPU Memory Usage totalUsageInBytes %.3f MB aliasableUsageInBytes %.3f MB", memoryUsage.totalUsageInBytes / 1048576.f, memoryUsage.aliasableUsageInBytes / 1048576.f);4. Debugging
4.1. Debug view
When the FSR™ Ray Regeneration context is created with FFX_DENOISER_ENABLE_DEBUGGING, integrations can pass an optional ffxDispatchDescDenoiserDebugView dispatch description to ffxDispatch to output relevant debug information into an app-provided render target.
Figure 2: FSR™ Ray Regeneration debug view in overview mode.
| Data | Description |
|---|---|
Motion Vectors | Pixel screen motion, the XY-components of the motionVectors input. |
Motion Vectors Z | Pixel z motion (i.e. signed linear depth delta), the Z-component of the motionVectors input.Blue for negative deltas, Red for positive deltas. |
Linear Depth | Absolute value of the linearDepth input.Clamped to linearDepthBounds. |
Normals | Decoded normals of the normals input. |
Reprojected Confidence | Indicates the per pixel confidence of a history sample. Black means the sample will not contribute in the accumulation. |
Reprojected UV | UV that will be used to sample history information. |
View Centered Pos | Reconstructed position centered around the camera. This information is useful to validate that input camera parameters are correct. |
Virtual Hit Pos | Reconstructed virtual hit position used for low-roughness specular samples. This information is useful to validate that input camera parameters and specular ray length are correct. |
NN Input0 | First input channel to the neural network. |
NN Input1 | Second input channel to the neural network. |
NN Input2 | Third input channel to the neural network. |
Composed Luma | Luminance of the composited input signals. |
Passing a ffxDispatchDescDenoiserDebugView dispatch description to ffxDispatch automatically enables the debug pass internally.
Output information is written to an app-provided render target and it is therefore up to the app itself to implement how to composite the output information to the screen.
FSR™ Ray Regeneration expects the output target to be in a 4-component format as all four data components are used.
In the output target the RGB channels contains the color information to display and the A channel indicates which pixels have been written to.
The mode parameter toggles between an overview mode or fullscreen mode of a single data viewport.
The viewportIndex controls which viewport to display if FFX_API_DENOISER_DEBUG_VIEW_MODE_FULLSCREEN_VIEWPORT is selected as the active mode.
The viewportIndex is clamped between 0 and FFX_API_DENOISER_DEBUG_VIEW_MAX_VIEWPORTS - 1.
// Example: populating the debug view dispatch description.ffx::DispatchDescDenoiserDebugView dispatchDenoiserDebugView = {};dispatchDenoiserDebugView.output = SDKWrapper::ffxGetResourceApi(m_pDebugView->GetResource(), FFX_API_RESOURCE_STATE_UNORDERED_ACCESS);dispatchDenoiserDebugView.outputSize = { m_pDebugView->GetDesc().Width, m_pDebugView->GetDesc().Height };dispatchDenoiserDebugView.mode = m_DebugViewMode;dispatchDenoiserDebugView.viewportIndex = (uint32_t)m_DebugViewport;4.1.1. ffxDispatchDescDenoiserDebugView
| Parameter | Description |
|---|---|
output | Target output resource to write debug visualization data into. |
outputSize | The resolution of the output resource. |
mode | An entry of FfxApiDenoiserDebugViewMode that selects the mode used for visualization.FFX_API_DENOISER_DEBUG_VIEW_MODE_OVERVIEWFFX_API_DENOISER_DEBUG_VIEW_MODE_FULLSCREEN_VIEWPORT |
viewportIndex | When mode is set to FFX_API_DENOISER_DEBUG_VIEW_MODE_FULLSCREEN_VIEWPORT, use this index to indicate which debug viewport to fullscreen.The value is clamped between 0 and FFX_API_DENOISER_DEBUG_VIEW_MAX_VIEWPORTS - 1 |
5. Best practices
5.1. Generating noisy signals
FSR™ Ray Regeneration expects one or more low-sample radiance and/or occlusion input signals for denoising, depending on the selected signals at context creation. High-quality inputs are essential to achieve the best results, as the algorithm is not designed to “correct” artefacts present in the input data. Below are some guidelines for generating high-quality noisy inputs.
5.1.1. Stochastic sampling
In most physically-based path tracers, stochastic sampling is used to simulate realistic lighting behaviors such as shadows, reflections, and indirect lighting. Stochastic sampling introduces randomness into ray directions so that, over many samples, the result converges to a noise-free signal. At low sample counts, this randomness produces perceivable noise in the rendered image. This noise is exactly what FSR™ Ray Regeneration targets for denoising. Understanding and managing the quality of this noise is critical for achieving optimal denoising results.
| Noisy Input | Denoised Output |
|---|---|
| |
Figure 3: left: Noisy ray-traced input to FSR™ Ray Regeneration. right: Corresponding denoised output from FSR™ Ray Regeneration.
5.1.2. Noise
We recommend using white noise and high-quality hash functions with minimal correlations when driving stochastic sampling.
Examples of suitable hash functions include xxhash32 and lowbias32.
A good practice is to ensure that your ray-traced image converges to a noise-free result when using many samples without denoising. If it does not, verify whether your chosen noise or hash function is introducing unwanted correlations or other artifacts that are difficult to denoise.
While blue noise often performs well in many scenarios, it can introduce correlation artifacts if its period is not sufficiently large. For this reason, white noise is generally preferred for FSR™ Ray Regeneration inputs.
Noise reduction techniques such as ReSTIR can help reduce noise in the input signals. However, these techniques often introduce cross-sample dependencies that FSR™ Ray Regeneration is not designed to handle. In such cases, it is important to disrupt correlation patterns using strategies like permutation sampling or randomization of temporal reuse.
5.1.3. Usage of radiance caching
Tracing paths recursively quickly becomes too expensive for real-time rendering. To manage this cost, many real-time path tracers apply radiance caching after only a few recursive bounces. Radiance caching provides a precomputed store of radiance that can be sampled by direction, enabling early ray termination and significantly reducing computational overhead.
Using a radiance cache generally results in a more complete signal, since additional lighting contributions, too expensive to compute per frame, are incorporated through cached samples. This is naturally beneficial for FSR™ Ray Regeneration, as more complete inputs typically yield more complete and stable outputs.
However, the caching process often trades accuracy for performance, which may introduce artifacts into the final image. Watch out for low-frequency noise or temporal inconsistencies, as these issues can be amplified by the denoiser if not mitigated.
See AMD GI-1.0 for examples and guidance on radiance caching.
5.1.4. Tweakable denoiser settings
Even with high-quality inputs and the recommended best practices applied, some artifacts may still remain.
FSR™ Ray Regeneration exposes a number of tweakable settings, defined in FfxApiConfigureDenoiserKey, that allow fine-grained control over denoiser behavior.
These parameters can help balance stability, sharpness, and noise reduction to best suit your application.
It is recommended to start from the default settings queried from the API and then adjust selectively according to what works best for your application. For the full list of available keys and guidance on retrieving and applying these settings, see 2.6. Configuring settings.
5.2. Providing motion vectors
5.2.1. Space
A key part of any temporal algorithm is the provision of motion vectors.
FSR™ Ray Regeneration accepts motion vectors in a 2.5D format:
- The
XYcomponents represent screen-space pixel motion, encoding the movement from a pixel in the current frame to the same pixel in the previous frame. - The
Zcomponent represents the signed linear view-spacezdelta.
Figure 4: A 2D motion vector from a pixel in the current frame to the corresponding pixel in the previous frame.
If your application computes motion vectors in a space other than UV space (for example, NDC space), you can use the motionVectorScale member of the ffxDispatchDescDenoiser dispatch description to scale them appropriately for FSR™ Ray Regeneration.
Example HLSL and C++ code illustrating NDC-space motion vector scaling:
// GPU: Example of NDC motion vector computation
float3 motionVector;
// 2D motion expressed in NDC spacemotionVector.xy = (previousPosition.xy / previousPosition.w) - (currentPosition.xy / currentPosition.w) - cancelJitter;
// Assuming camera looks along the +Z axis in view space: pView.z = pProjection.w// Signed linear depth deltamotionVector.z = previousPosition.w - currentPosition.w;// CPU: Matching FSR™ Ray Regeneration motionVectorScale configuration to convert motion vectors from NDC to UV spacedispatchDesc.motionVectorScale.x = +0.5f;dispatchDesc.motionVectorScale.y = -0.5f;
dispatchDesc.motionVectorScale.z = +1.0f;5.2.2. Coverage
FSR™ Ray Regeneration achieves higher-quality denoising when more objects provide valid motion vectors. It is therefore recommended that all opaque, alpha-tested, and alpha-blended objects write motion vectors for every pixel they cover. Additionally, if vertex shader effects are applied, such as scrolling UVs or procedural vertex animations, these transformations should also be incorporated into the motion vector computation to ensure optimal results.
5.3. Encoding normals
Each 3D normal vector represents a direction on the unit sphere. To store normals efficiently, we can project the unit sphere onto a 2D plane and remap each normal vector as a 2D UV coordinate. This process is called octahedral encoding. The normals passed to FSR™ Ray Regeneration are required to be stored using octahedral encoding.
Below are examples of how to encode and decode normals using this method.
5.3.1. Octahedral encoding of normals:
// Example: encoding a unit normal vector into a 2D octahedral UV.float2 NormalToOctahedronUv(float3 N){ N.xy /= abs(N.x) + abs(N.y) + abs(N.z); float2 k = sign(N.xy); float s = saturate(-N.z); N.xy = lerp(N.xy, (1.0 - abs(N.yx)) * k, s); return N.xy * 0.5 + 0.5;}5.3.2. Octahedral decoding of normals:
// Example: decoding a 2D octahedral UV back into a unit normal vector.float3 OctahedronUvToNormal(float2 UV){ UV = UV * 2.0f - 1.0f; float3 N = float3(UV, 1.0f - abs(UV.x) - abs(UV.y)); float t = saturate(-N.z); float2 s = sign(N.xy); N.xy += s * t; return normalize(N);}5.4. Encoding material type
The alpha channel of the normals member of the ffxDispatchDescDenoiser dispatch description is used to encode the material type.
The material type is a lightweight way to distinguish different surface materials from one another.
FSR™ Ray Regeneration will reject mixing between two pixels if their material IDs do not match.
This prevents cross-material blending and is an effective solution for avoiding ghosting artifacts in complex material setups.
FSR™ Ray Regeneration supports four material type values (0–3).
Material type 0 is reserved as the default material, leaving three additional values available for custom use.
Upon encoding the material type into the normals member of the ffxDispatchDescDenoiser dispatch description, the stored value should be a normalized fraction relative to the maximum number of supported materials.
// Example: encoding the material type into the alpha channel of the normals resource.// ... ray tracing pass ...
uint materialType = hit.materialType;float materialTypeFrac = materialType / 3.0;
outNormalsResource[pixel] = float4(normalOctahedralUv, roughness, materialTypeFrac);5.5. Generating specular albedo
Specular albedo can be generated using various methods. In most physically-based rendering pipelines, similar computations are already performed as part of the lighting computations. These computations can be reused to generate a standalone specular albedo feature map.
Below are two commonly used methods for generating specular albedo in real-time rendering applications.
5.5.1. Example: BRDF lookup table
A BRDF LUT is generated offline and stored in a floating-point texture. At runtime, this LUT is sampled to look up approximate BRDF characteristics, commonly used in the split-sum approximation for image-based lighting.
Figure 5: A typical GGX BRDF look-up table.
The following HLSL code snippet illustrates how to sample the BRDF LUT and use the resulting scale and bias to generate specular albedo:
// Example: generating specular albedo from a pre-baked GGX BRDF look-up table.// ... ray tracing pass ...
float NoV = dot(normal, view);float2 brdf = BrdfLUT.SampleLevel(LinearSampler, float2(NoV, hit.materialRoughness), 0);
const float3 MinReflectance = float3(0.04, 0.04, 0.04);float3 F0 = lerp(MinReflectance, hit.materialAlbedo.rgb, hit.materialMetallic);float3 specularAlbedo = F0 * brdf.x + brdf.y;
// ...5.5.2. Example: BRDF Approximation
The following HLSL code snippets illustrate how to approximate the BRDF contribution at runtime without the need for an offline baked LUT:
// [Ray Tracing Gems, Chapter 32]float3 ApproximateBRDF(float3 F0, float alpha, float NoV){ NoV = abs(NoV); float4 x = float4(1.0, NoV, NoV*NoV, NoV*NoV*NoV); float4 y = float4(1.0, alpha, alpha*alpha, alpha*alpha*alpha);
float2x2 M1 = float2x2(0.99044, -1.28514, 1.29678, -0.755907);
float3x3 M2 = float3x3(1.0, 2.92338, 59.4188, 20.3225, -27.0302, 222.592, 121.563, 626.13, 316.627);
float2x2 M3 = float2x2(0.0365463, 3.32707, 9.0632, -9.04756);
float3x3 M4 = float3x3(1.0, 3.59685, -1.36772, 9.04401, -16.3174, 9.22949, 5.56589, 19.7886, -20.2123);
float bias = dot(mul(M1, x.xy), y.xy) * rcp(dot(mul(M2, x.xyw), y.xyw)); float scale = dot(mul(M3, x.xy), y.xy) * rcp(dot(mul(M4, x.xzw), y.xyw));
// Hack for specular reflectance of 0 bias *= saturate(F0.g * 50); return mad(F0, max(0, scale), max(0, bias));}
// ... ray tracing pass ...
const float3 MinReflectance = float3(0.04, 0.04, 0.04);float3 F0 = lerp(MinReflectance, hit.materialAlbedo.rgb, hit.materialMetallic);
float alpha = hit.materialRoughness * hit.materialRoughness;float NoV = dot(normal, view);
float3 specularAlbedo = ApproximateBRDF(F0, alpha, NoV);
// ...6. Requirements
- AMD FSR™ Ray Regeneration requires an AMD Radeon™ RX 9000 Series GPU or later.
- DirectX® 12 + Shader Model 6.6
- Windows® 11
7. Version history
For more details, refer to the changelog.