NVIDIA NRD: Real-Time Path Tracing Without the Noise Nightmare
NVIDIA NRD: Real-Time Path Tracing Without the Noise Nightmare
Your path tracer looks gorgeous at 4096 samples per pixel. But at 1 sample per pixel? It's a snowstorm of visual garbage. Fireflies explode across the screen. Shadows dissolve into static. Reflections flicker like a dying fluorescent tube. You've tried bilateral filters. You've prayed to TAA gods. You've even considered telling your art director that "grainy" is now an aesthetic choice.
Stop. There's a better way—and it's not another half-baked blur pass that murders your contact shadows.
Enter NVIDIA Real-Time Denoisers (NRD). This isn't some research demo that runs at 12 FPS on a lab machine. NRD is a battle-tested, API-agnostic spatio-temporal denoising library powering 15+ AAA game titles and professional visualization applications like Autodesk Aurora, Enscape, and Lumion. It transforms path-traced signals from unusable noise into production-ready imagery in milliseconds, not minutes. And here's the kicker: its modern Spherical Harmonics (SH) mode achieves quality comparable to DLSS Ray Reconstruction—offering a powerful, non-AI alternative that holds its own in an AI-dominated world.
Ready to finally make real-time path tracing work? Let's dive deep.
What is NVIDIA NRD?
NVIDIA Real-Time Denoisers (NRD) is a spatio-temporal denoising library specifically engineered for high-quality denoising of noisy signals, with primary focus on 1 path/pixel path tracing. Currently at version 4.17.4, NRD represents years of refinement from NVIDIA's graphics research division, distilled into a production-ready SDK that any developer can integrate.
What makes NRD genuinely special? It's API-agnostic by design. Whether your engine runs on DirectX 12, Vulkan, or even legacy DirectX 11, NRD slides right in without dictating your renderer architecture. It leverages per-pixel G-buffer guides—normal, roughness, view-space Z, and motion vectors—to intelligently resolve noise on opaque surfaces while respecting geometric boundaries and material properties.
The library's credibility isn't theoretical. NRD ships in shipping products right now. Autodesk Aurora uses it for architectural visualization. Enscape leverages it for real-time rendering. Lumion integrated it for ray-traced previews. These aren't tech demos—they're tools used by professionals who can't afford to ship broken visuals.
NRD's modern "SH" mode is particularly noteworthy. By using Spherical Gaussian (SG) representations internally, it achieves quality that NVIDIA themselves compare favorably against DLSS-RR. For developers who can't or won't require RTX-specific AI features, or who need cross-platform consistency, this is huge. You get reconstruction quality that rivals machine learning approaches, but with deterministic performance, no neural network inference overhead, and full control over the algorithmic pipeline.
The library includes three distinct denoisers, each optimized for specific signal types: REBLUR (recurrent blur-based), RELAX (A-trous wavelet-based, designed for RTXDI), and SIGMA (per-light shadow denoiser). This modular approach lets you deploy exactly the right tool for each lighting component rather than forcing a one-size-fits-all solution.
Key Features That Separate NRD from Amateur Hour
Three Specialized Denoisers, One Coherent Framework
REBLUR dominates for general diffuse and specular radiance denoising, with variants for occlusion signals and directional occlusion. Its recurrent blur architecture delivers exceptional stability for indirect lighting. RELAX, built around A-trous wavelets, shines with RTXDI-produced signals and cleaner high-sample-count inputs. SIGMA handles shadow denoising with surgical precision—supporting both infinite lights (sun, moon) and local lights (omni, spot), plus translucency.
Spherical Harmonics Mode: The Secret Weapon
NRD's SH variants don't just denoise color—they preserve directional lighting information. This enables post-denoise resolve operations that reconstruct macro-details and micro-details lost in traditional denoising. When combined with upscalers like DLSS, FSR, or XeSS, this means you can denoise at lower resolutions and still recover crisp detail. The SG-based representation is mathematically elegant and computationally efficient.
Material Demodulation Architecture
NRD expects radiance, not irradiance. This means your path tracer must decouple material BRDFs from the signal before denoising, then reapply them after. While this requires pipeline changes, the payoff is massive: denoisers work with physically meaningful quantities instead of material-modulated mush. The NRD_MaterialFactors helper in NRD.hlsli automates the conversion math.
Validation Layer for Debugging Sanity
Enable CommonSettings::enableValidation and NRD renders a comprehensive debug overlay—16 viewports showing normals, roughness, viewZ, motion vector accuracy, virtual history amounts, accumulated frame counts, and normalized hit distances. This isn't printf debugging; it's a visual profiler that immediately reveals integration mistakes.
Performance That Doesn't Make You Cry
On RTX 4080 at 1440p native: REBLUR_DIFFUSE_SPECULAR hits 2.50 ms (3.40 ms in SH mode). RELAX_DIFFUSE_SPECULAR runs at 3.20 ms (4.80 ms SH). SIGMA_SHADOW? A mere 0.40 ms. These aren't theoretical peaks—they're measured with practical settings including anti-firefly filtering and 3x3 hit distance reconstruction.
Real-World Use Cases Where NRD Transforms Possibilities
AAA Game Development with Real-Time Path Tracing
The obvious home run. Modern titles increasingly adopt path tracing for global illumination, but 1 spp is all the GPU budget allows. NRD makes this viable. REBLUR stabilizes diffuse bounces across frames while preserving contact shadow detail. Specular denoising maintains reflection clarity without the smeared Vaseline look of spatial-only filters. The SH mode's compatibility with DLSS means you can path trace at quarter resolution, denoise, upscale, and resolve—hitting 60 FPS with image quality that rivals offline renders.
Architectural Visualization and ProVis
Autodesk Aurora and Enscape prove NRD's value outside games. Architects need interactive lighting studies that don't lie. Traditional rasterized GI approximations fail for complex material interactions. Path tracing with NRD denoising gives physically accurate results at interactive rates, letting designers iterate on lighting in real-time rather than waiting for offline bakes.
Virtual Production and Film Previz
LED volume stages and virtual sets demand real-time ray tracing for accurate camera tracking and lighting matching. NRD's temporal stability prevents the flicker that breaks immersion on massive screens. The validation layer helps technical directors verify integration correctness under production pressure.
Product Design and Automotive Rendering
Car configurators and product showcases need flawless reflections. NRD's specular denoising handles curved surfaces, anisotropic materials, and complex BRDFs that simple filters destroy. The PSR (Primary Surface Replacement) support enables accurate mirror reflections through multiple bounces.
Cloud Rendering and Streaming Services
When every millisecond of GPU time costs money, NRD's efficiency matters. SIGMA's per-light shadow denoising with maxStabilizedFrameNum = 0 enables light-count-independent memory usage—critical for multi-tenant cloud rendering where memory overcommit kills margins.
Step-by-Step Installation & Setup Guide
Prerequisites
- CMake 3.22+ installed and in PATH
- Git for submodule initialization
- Windows: Visual Studio 2022 or compatible compiler
- Vulkan SDK or Windows SDK with D3D12/D3D11 support
Build Process
Variant 1: Explicit Git + CMake
# Clone with submodules
git clone --recursive https://github.com/NVIDIA-RTX/NRD.git
cd NRD
# Generate build files (adjust generator as needed)
cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DNRD_NRI=ON
# Build
cmake --build build --config Release
Variant 2: Convenience Scripts
# Windows: run the provided batch scripts
1-Deploy.bat # Generates project files
2-Build.bat # Compiles Release and Debug
Critical CMake Options
| Option | Default | Purpose |
|---|---|---|
NRD_NRI |
OFF | Enable this! Pulls and builds NRI for integration layer |
NRD_EMBEDS_DXIL_SHADERS |
ON (Win) | Embeds precompiled DXIL shaders |
NRD_EMBEDS_SPIRV_SHADERS |
ON | Embeds SPIRV for Vulkan |
NRD_NORMAL_ENCODING |
varies | Match your G-buffer normal format |
NRD_ROUGHNESS_ENCODING |
varies | Match your roughness format |
REBLUR_PERFORMANCE_MODE |
OFF | Console/performance builds |
SDK Packaging for Distribution:
# After building both Debug and Release
3-PrepareSDK.bat
# Grab generated folders:
# ./_NRD_SDK - NRD headers, libs, shaders
# ./_NRI_SDK - NRI abstraction layer (if NRD_NRI=ON)
Integration Architecture Decision
You have two paths:
-
NRI-based integration (recommended): Expose native D3D12/Vulkan/D3D11 pointers through NRI. The
NRDIntegrationlayer handles all resource management, descriptor heaps, and dispatch scheduling. -
Native API implementation: Implement the NRD API directly using your engine's RHI. More work, but zero abstraction overhead.
For most teams, path 1 saves weeks of integration pain. The NRI abstraction is thin and Vulkan-influenced—you're not hiding from the GPU, just standardizing object lifetimes.
REAL Code Examples from the Repository
Example 1: D3D12 Integration Setup with NRI
This is the production integration pattern from NRDIntegration.hpp, adapted for clarity:
//=======================================================================================================
// DECLARATIONS (using D3D12 as an example)
//=======================================================================================================
#include "NRI.h"
#include "Extensions/NRIHelper.h"
#include "Extensions/NRIWrapperD3D12.h" // Or VK, D3D11 wrappers
#include "NRD.h"
#include "NRDIntegration.hpp"
nrd::Integration NRD = {};
// Converts an app-side texture into an NRD resource descriptor
nrd::Resource GetNrdResource(MyTexture& myTexture) {
nrd::Resource resource = {};
resource.d3d12.resource = myTexture.GetD3D12Resource(); // Native D3D12 resource pointer
resource.d3d12.format = myTexture.GetFormat(); // DXGI format for validation
resource.userArg = &myTexture; // Round-trip pointer for state tracking
resource.state = myTexture->state; // "last after" state for barrier management
return resource;
}
//=======================================================================================================
// INITIALIZATION
//=======================================================================================================
// Describe your D3D12 queue to NRI
nri::QueueFamilyD3D12Desc queueFamilyD3D12Desc = {};
queueFamilyD3D12Desc.d3d12Queues = &d3d12Queue;
queueFamilyD3D12Desc.queueNum = 1;
queueFamilyD3D12Desc.queueType = nri::QueueType::GRAPHICS; // or COMPUTE
// Wrap your existing D3D12 device
nri::DeviceCreationD3D12Desc deviceCreationD3D12Desc = {};
deviceCreationD3D12Desc.d3d12Device = d3d12Device;
deviceCreationD3D12Desc.queueFamilies = &queueFamilyD3D12Desc;
deviceCreationD3D12Desc.queueFamilyNum = 1;
// Configure which denoisers you need
const nrd::DenoiserDesc denoiserDescs[] =
{
{ identifier1, nrd::Denoiser::REBLUR_DIFFUSE_SPECULAR },
{ identifier2, nrd::Denoiser::SIGMA_SHADOW },
};
nrd::InstanceCreationDesc instanceCreationDesc = {};
instanceCreationDesc.denoisers = denoiserDescs;
instanceCreationDesc.denoisersNum = 2;
// Integration settings control resource allocation strategy
nrd::IntegrationCreationDesc integrationCreationDesc = {};
strncpy(integrationCreationDesc.name, "NRD", sizeof(integrationCreationDesc.name));
integrationCreationDesc.queuedFrameNum = 3; // Frames in-flight (match your swap chain)
integrationCreationDesc.enableWholeLifetimeDescriptorCaching = false; // Safer for development
integrationCreationDesc.autoWaitForIdle = true; // Simpler sync, slight overhead
// Pre-allocate resources at maximum resolution
// Dynamic resolution scaling adjusts via CommonSettings::rectSize later
integrationCreationDesc.resourceWidth = resourceWidth;
integrationCreationDesc.resourceHeight = resourceHeight;
// Create everything in one call
nrd::Result result = NRD.RecreateD3D12(
integrationCreationDesc,
instanceCreationDesc,
deviceCreationD3D12Desc
);
Why this matters: The RecreateD3D12 call builds the entire internal texture pool, pipeline state objects, and descriptor heaps. The queuedFrameNum = 3 matches triple-buffering—critical for avoiding GPU idle bubbles. Note that NRD doesn't support resize; you destroy and recreate on resolution changes.
Example 2: Per-Frame Denoising Dispatch
//=======================================================================================================
// PREPARE - Called once per frame, before denoising
//=======================================================================================================
NRD.NewFrame(); // Must be called first! Rotates internal history buffers
// Common settings shared across all denoisers in the instance
nrd::CommonSettings commonSettings = {};
PopulateCommonSettings(commonSettings); // Your function: set resolution, matrices, MV scale, etc.
NRD.SetCommonSettings(commonSettings);
// Per-denoiser tunable settings
nrd::ReblurSettings reblurSettings = {};
reblurSettings.enableAntiFirefly = true; // +0-2% overhead, removes fireflies
PopulateReblurSettings(reblurSettings);
NRD.SetDenoiserSettings(identifier1, &reblurSettings);
nrd::SigmaSettings sigmaSettings = {};
PopulateSigmaSettings(sigmaSettings);
NRD.SetDenoiserSettings(identifier2, &sigmaSettings);
//=======================================================================================================
// RENDER - Bind resources and dispatch
//=======================================================================================================
nrd::ResourceSnapshot resourceSnapshot = {};
{
// Automatic state restoration (simpler but adds barriers)
resourceSnapshot.restoreInitialState = true;
// REQUIRED: G-buffer guides for all denoisers
resourceSnapshot.SetResource(nrd::ResourceType::IN_MV,
GetNrdResource(myTexture_MotionVectors));
resourceSnapshot.SetResource(nrd::ResourceType::IN_NORMAL_ROUGHNESS,
GetNrdResource(myTexture_NormalRoughness));
resourceSnapshot.SetResource(nrd::ResourceType::IN_VIEWZ,
GetNrdResource(myTexture_ViewZ));
// Denoiser-specific inputs
resourceSnapshot.SetResource(nrd::ResourceType::IN_DIFF_RADIANCE_HITDIST,
GetNrdResource(myTexture_DiffuseNoisy));
resourceSnapshot.SetResource(nrd::ResourceType::IN_SPEC_RADIANCE_HITDIST,
GetNrdResource(myTexture_SpecularNoisy));
resourceSnapshot.SetResource(nrd::ResourceType::IN_SHADOWDATA,
GetNrdResource(myTexture_ShadowNoisy));
// Output destinations
resourceSnapshot.SetResource(nrd::ResourceType::OUT_DIFF_RADIANCE_HITDIST,
GetNrdResource(myTexture_DiffuseDenoised));
resourceSnapshot.SetResource(nrd::ResourceType::OUT_SPEC_RADIANCE_HITDIST,
GetNrdResource(myTexture_SpecularDenoised));
resourceSnapshot.SetResource(nrd::ResourceType::OUT_SHADOW,
GetNrdResource(myTexture_ShadowDenoised));
}
// Execute! NRD binds its own descriptor heap and root signature
nri::CommandBufferD3D12Desc commandBufferD3D12Desc = {};
commandBufferD3D12Desc.d3d12CommandList = d3d12CommandList;
const nrd::Identifier denoisers[] = {identifier1, identifier2};
NRD.DenoiseD3D12(denoisers, 2, commandBufferD3D12Desc, resourceSnapshot);
// CRITICAL: Restore your descriptor heap and root signature!
// NRD integration changed them internally
Key insight: The ResourceSnapshot is NRD's contract with your renderer. You declare which textures serve which semantic roles, and NRD handles all SRV/UAV creation and binding. The restoreInitialState flag trades barrier efficiency for simplicity—disable it and manually track states via resourceSnapshot.unique[] for production.
Example 3: Shader Front-End—Packing Path Traced Data
This HLSL from NRD.hlsli shows how to prepare your path tracer's output for NRD consumption:
#include "NRD.hlsli"
// Your path tracer accumulates radiance and hit distances per pixel
Out out = (Out)0;
// Track accumulated hit distance for reprojection quality
float accumulatedHitDist = 0;
float3 ray1 = 0; // First bounce direction for SH mode
// Primary hit (PSR or direct surface)
Hit primaryHit; // Your G-buffer data
// Path loop: typically 1 spp for real-time, more for reference
for (int path = 0; path < pathNum; path++)
{
for (int bounce = 1; bounce <= bounceMaxNum; bounce++)
{
// ... your path tracing logic ...
// Accumulate hit distance along the path
// NRD uses this for specular tracking and motion vector estimation
if (bounce == 1)
accumulatedHitDist = hitDist;
// Save first bounce direction for SH denoisers
if (bounce == 1 && SH)
ray1 = ray;
}
// Normalize hit distances for REBLUR's internal representation
float normHitDist = accumulatedHitDist;
if (REBLUR)
{
normHitDist = REBLUR_FrontEnd_GetNormHitDist(
accumulatedHitDist,
primaryHit.viewZ,
gHitDistSettings, // Per-scene tuning parameters
isDiffusePath ? 1.0 : primaryHit.roughness
);
}
// Separate diffuse and specular contributions
if (isDiffusePath)
{
out.diffRadiance += Lsum;
out.diffHitDist += normHitDist;
if (SH)
out.diffDirection += ray1;
}
else
{
out.specRadiance += Lsum;
out.specHitDist += normHitDist;
if (SH)
out.specDirection += ray1;
}
}
// Average across paths (radiance includes sampling probability)
float invPathNum = 1.0 / float(pathNum);
out.diffRadiance *= invPathNum;
out.specRadiance *= invPathNum;
// Hit distances average only across valid paths of each lobe type
float diffNorm = diffPathNum ? 1.0 / float(diffPathNum) : 0.0;
out.diffHitDist *= diffNorm;
if (SH)
out.diffDirection *= diffNorm;
// MATERIAL DEMODULATION: Convert irradiance to radiance
// NRD expects pure radiance, not material-modulated color
float3 diffFactor, specFactor;
NRD_MaterialFactors(
primaryHit.N, primaryHit.V,
primaryHit.albedo, primaryHit.Rf0, primaryHit.roughness,
diffFactor, specFactor
);
out.diffRadiance /= diffFactor; // Remove diffuse albedo
out.specRadiance /= specFactor; // Remove specular BRDF scaling
// Pack into NRD's expected format
float4 outDiff = 0.0;
float4 outSpec = 0.0;
float4 outDiffSh = 0.0;
float4 outSpecSh = 0.0;
if (RELAX)
{
if (SH)
{
outDiff = RELAX_FrontEnd_PackSh(
out.diffRadiance, out.diffHitDist, out.diffDirection,
outDiffSh, USE_SANITIZATION
);
outSpec = RELAX_FrontEnd_PackSh(
out.specRadiance, out.specHitDist, out.specDirection,
outSpecSh, USE_SANITIZATION
);
}
else
{
outDiff = RELAX_FrontEnd_PackRadianceAndHitDist(
out.diffRadiance, out.diffHitDist, USE_SANITIZATION
);
outSpec = RELAX_FrontEnd_PackRadianceAndHitDist(
out.specRadiance, out.specHitDist, USE_SANITIZATION
);
}
}
else // REBLUR
{
if (SH)
{
outDiff = REBLUR_FrontEnd_PackSh(
out.diffRadiance, out.diffHitDist, out.diffDirection,
outDiffSh, USE_SANITIZATION
);
outSpec = REBLUR_FrontEnd_PackSh(
out.specRadiance, out.specHitDist, out.specDirection,
outSpecSh, USE_SANITIZATION
);
}
else
{
outDiff = REBLUR_FrontEnd_PackRadianceAndNormHitDist(
out.diffRadiance, out.diffHitDist, USE_SANITIZATION
);
outSpec = REBLUR_FrontEnd_PackRadianceAndNormHitDist(
out.specRadiance, out.specHitDist, USE_SANITIZATION
);
}
}
Critical understanding: The NRD_MaterialFactors demodulation is non-negotiable. Without it, NRD denoises albedo-modulated color, causing color bleeding across material boundaries and destroying energy conservation. The USE_SANITIZATION flag enables NaN/INF clearing—essential for robustness with adversarial path tracer inputs.
Example 4: SH Resolve with Upscaler Integration
After denoising, reconstruct detail for DLSS/FSR/XeSS:
// Read denoised outputs
float4 diff = gIn_Diff[pixelPos];
float4 diff1 = gIn_DiffSh[pixelPos];
NRD_SG diffSg = REBLUR_BackEnd_UnpackSh(diff, diff1);
float4 spec = gIn_Spec[pixelPos];
float4 spec1 = gIn_SpecSh[pixelPos];
NRD_SG specSg = REBLUR_BackEnd_UnpackSh(spec, spec1);
// REGAIN MACRO-DETAILS lost in SH representation
diff.xyz = NRD_SG_ResolveDiffuse(diffSg, N);
spec.xyz = NRD_SG_ResolveSpecular(specSg, N, V, roughness);
// REGAIN MICRO-DETAILS and per-pixel jitter for upscalers
// Sample neighbor normals and depths for curvature estimation
float3 Ne = NRD_FrontEnd_UnpackNormalAndRoughness(
gIn_Normal_Roughness[pixelPos + int2(1, 0)]).xyz;
float3 Nw = NRD_FrontEnd_UnpackNormalAndRoughness(
gIn_Normal_Roughness[pixelPos + int2(-1, 0)]).xyz;
float3 Nn = NRD_FrontEnd_UnpackNormalAndRoughness(
gIn_Normal_Roughness[pixelPos + int2(0, 1)]).xyz;
float3 Ns = NRD_FrontEnd_UnpackNormalAndRoughness(
gIn_Normal_Roughness[pixelPos + int2(0, -1)]).xyz;
float Ze = gIn_ViewZ[pixelPos + int2(1, 0)];
float Zw = gIn_ViewZ[pixelPos + int2(-1, 0)];
float Zn = gIn_ViewZ[pixelPos + int2(0, 1)];
float Zs = gIn_ViewZ[pixelPos + int2(0, -1)];
// Compute re-jittering scale based on local curvature
float2 scale = NRD_SG_ReJitter(
diffSg, specSg, V, roughness, viewZ,
Ze, Zw, Zn, Zs, N, Ne, Nw, Nn, Ns
);
diff.xyz *= scale.x;
spec.xyz *= scale.y;
// REMODULATE: Convert radiance back to irradiance for shading
float3 diffFactor, specFactor;
NRD_MaterialFactors(N, V, albedo, Rf0, roughness, diffFactor, specFactor);
diff.xyz *= diffFactor;
spec.xyz *= specFactor;
Why this works: The SG resolve reconstructs directional variation that spatial blurring destroyed. Re-jittering restores sub-pixel detail that upscalers need for their own temporal accumulation. Without this step, SH-denoised images look artificially smooth under DLSS.
Advanced Usage & Best Practices
History Confidence: The Performance Multiplier
Don't rely solely on REBLUR/RELAX built-in anti-lag. Compute IN_DIFF_CONFIDENCE and IN_SPEC_CONFIDENCE based on gradients between previous-frame stored radiance and current-frame reprojected radiance. This costs <5% frame time but dramatically improves responsiveness. Use spatial blur (5 passes of 5x5) rather than temporal accumulation for gradient filtering—temporal accumulation lags behind lighting changes.
Blue Noise: Not Just for Instagram
NRD handles white noise baseline, but blue noise improves spatial filter efficiency. Use Owen-scrambled Sobol sequences with 64x64+ screen-space extent. Match sequence length to NRD's max history (32 spp baseline). Critical for SIGMA shadow denoising and REBLUR occlusion modes.
Hit Distance: The Hidden Variable
NRD's behavior is driven by hit distances, not just color. For specular, always use indirect hitT even when denoising combined direct+indirect lighting—direct light selection often picks diffuse-contributing lights, confusing specular reprojection. For probabilistic lobe selection, enable HitDistanceReconstructionMode::AREA_3X3 and prepass blur to compensate for zero-hitT neighbors.
Primary Surface Replacements for Perfect Mirrors
For glass and mirror materials, implement PSR to let NRD "see through" delta events. Replace primary hit data with the first non-mirror hit, adjusting viewZ, normals, and motion vectors into virtual space. This eliminates the "infinite reflection tunnel" problem without recursive tracing.
Frame Generation Awareness
When using DLSS Frame Generation or FSR3, pass real FPS to GetMaxAccumulatedFrameNum, not the interpolated rate. NRD's temporal accumulation runs on the base frame rate, not the displayed one.
Comparison with Alternatives
| Feature | NVIDIA NRD | Intel Open Image Denoise | AMD FidelityFX Denoiser | Custom Bilateral/ATrous |
|---|---|---|---|---|
| Real-time performance | ✅ 0.4-4.8ms | ❌ Offline/seconds | ✅ ~similar | ✅ Fast |
| Temporal accumulation | ✅ Native | ❌ Spatial only | ✅ Limited | ❌ Manual TAA hack |
| API agnostic | ✅ D3D11/12, Vulkan | ✅ CPU/GPU | ✅ GPU only | ✅ Any |
| Material demodulation | ✅ Designed for | ⚠️ Post-process | ❌ No | ❌ No |
| SH/directional denoising | ✅ SG-based | ❌ No | ❌ No | ❌ No |
| Shadow-specific denoiser | ✅ SIGMA | ❌ General purpose | ❌ No | ❌ No |
| Production proven | ✅ 15+ AAA titles | ✅ Films/VFX | ⚠️ Emerging | ❌ Varies |
| Non-AI deterministic | ✅ All modes | ✅ CPU | ✅ All | ✅ Yes |
| DLSS/FSR integration | ✅ SH resolve | ❌ N/A | ⚠️ Basic | ❌ Manual |
| Open source | ✅ BSD | ✅ Apache 2.0 | ✅ MIT | Varies |
Verdict: OIDN wins for offline quality but can't hit real-time budgets. AMD's denoiser is competent but lacks NRD's temporal sophistication and SH modes. Custom filters are fast but require months of tuning to approach NRD's stability. For real-time path tracing in production, NRD's combination of proven algorithms, explicit temporal design, and upscaler integration is unmatched.
FAQ: What Developers Actually Ask
Q: Does NRD require RTX hardware or DLSS?
No. NRD is fully deterministic and runs on any DX12/Vulkan/DX11 GPU. The SH mode's quality compares to DLSS-RR, but doesn't require tensor cores or neural network inference.
Q: How do I choose between REBLUR and RELAX?
REBLUR is the general-purpose workhorse—start here. RELAX excels with RTXDI signals or very clean inputs (high RPP). The NRD sample's simplex branch demonstrates both; benchmark in your specific content.
Q: Can NRD denoise volumetrics or transparency?
Not natively. For glass, the NRD sample shows a "denoising-free" path combining SHARC, reprojection, and TAA. For participating media, pre-integrate or use specialized volumetric denoisers.
Q: What's the memory overhead?
Depends on denoisers and resolution. REBLUR_DIFFUSE_SPECULAR SH at 1440p uses ~200-400MB for history buffers. SIGMA is negligible. See the README's memory usage table for exact numbers per configuration.
Q: How do I debug denoising artifacts?
Enable CommonSettings::enableValidation. The 16-viewport overlay immediately reveals bad motion vectors, incorrect normals, or insufficient history. Fix MV accuracy first—80% of artifacts stem from reprojection errors.
Q: Can I use NRD with dynamic resolution scaling?
Yes, via CommonSettings::rectSize and resourceSize. However, the NRD integration layer pre-allocates at fixed dimensions; true resize requires recreation. DRS within the allocated rectangle works seamlessly.
Q: Is the NRI abstraction layer mandatory?
No. Implement the NRD API directly if your RHI can't expose native pointers. NRD itself makes zero GAPI calls—you dispatch compute shaders manually. NRI just saves boilerplate.
Conclusion: Stop Accepting Noisy Path Tracing
NVIDIA NRD isn't a magic wand—it won't fix a fundamentally broken path tracer. But if you've done the work to implement importance sampling, separate diffuse and specular lobes, and feed proper G-buffer guides, NRD transforms your renderer from "tech demo" to "ship it."
The library's real power lies in its production maturity. This isn't theoretical research; it's code running in Autodesk Aurora, Enscape, and Lumion right now. The validation layer catches your integration mistakes. The SH mode rivals AI reconstruction without the black-box unpredictability. The performance budget—2.5ms for full diffuse+specular denoising at 1440p—fits comfortably in a 16ms frame.
For teams betting on real-time path tracing, NRD de-risks the hardest technical challenge: making 1 spp look like 1000. The alternative is months of custom filter development, endless artifact chasing, and explaining to stakeholders why reflections still flicker.
Don't build what NVIDIA already perfected. Grab the source, study the NRD sample, and integrate. Your art director—and your GPU budget—will thank you.
Star NRD on GitHub and start denoising like the pros.
Explore on the BrightCoding network
Hand-picked resources from our other sites.
Fantasy Map Generator: The World-Building Tool
Azgaar's Fantasy Map Generator revolutionizes world-building with procedural generation, interactive editing, and modern TypeScript architecture. Perfect for wr...
See-Through: The Secret Tool Decomposing Anime Into 2.5D Layers
Discover See-Through, the SIGGRAPH 2026 research project that automatically decomposes anime illustrations into 23 inpainted, semantically organized layers for...
Stop Wrestling with Physics Engines! Crashcat Makes JS Simulations Effortless
Discover crashcat, the pure JavaScript physics engine built for games, simulations, and creative websites. Learn why developers are abandoning WASM solutions fo...
Continuez votre lecture
Commentaires 0
Aucun commentaire pour l'instant. Soyez le premier à réagir !