Skip to content

Commit

Permalink
v3.9.1:
Browse files Browse the repository at this point in the history
HIGHLIGHTS:
- REBLUR: less history rejections and ghosting in certain cases
- README: various improvements

DETAILS:
- REBLUR: specular tracking improvements
- REBLUR: fix to skip HistoryFix if "history fix frame num" = 0
- REBLUR: fixed regression in resolution scale support
- SPECULAR_REFLECTION_MV: fixed regression in resolution scale support
- VALIDATION: fixed negative viewZ visualization
- README: added title image
- README: added validation layer image
- README: added "status badge"
- README: polishing
  • Loading branch information
dzhdanNV committed Nov 17, 2022
1 parent bb0f733 commit 8f8ce88
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 104 deletions.
2 changes: 1 addition & 1 deletion External/MathLib
Binary file added Images/Title.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/Validation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions Include/NRD.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.

#define NRD_VERSION_MAJOR 3
#define NRD_VERSION_MINOR 9
#define NRD_VERSION_BUILD 0
#define NRD_VERSION_DATE "11 November 2022"
#define NRD_VERSION_BUILD 1
#define NRD_VERSION_DATE "17 November 2022"

#if defined(_MSC_VER)
#define NRD_CALL __fastcall
Expand Down
92 changes: 51 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# NVIDIA Real-time Denoisers v3.9.0 (NRD)
# NVIDIA Real-time Denoisers v3.9.1 (NRD)

[![Build NRD SDK](https://github.com/NVIDIAGameWorks/RayTracingDenoiser/actions/workflows/build.yml/badge.svg)](https://github.com/NVIDIAGameWorks/RayTracingDenoiser/actions/workflows/build.yml)

![Title](Images/Title.jpg)

## SAMPLE APP

See *[NRD sample](https://github.com/NVIDIAGameWorks/NRDSample)* project.

## QUICK START GUIDE

### Intro
## OVERVIEW

*NVIDIA Real-Time Denoisers (NRD)* is a spatio-temporal API agnostic denoising library. The library has been designed to work with low rpp (ray per pixel) signals. *NRD* is a fast solution that slightly depends on input signals and environment conditions.

Expand All @@ -27,11 +29,13 @@ Supported signal types (modulated irradiance can be used instead of radiance):
- Shadows from a local light source (omni, spot)
- Shadows from multiple sources (experimental).

*NRD* is distributed as a source as well with a “ready-to-use” library (if used in a precompiled form). It can be integrated into any DX12, VULKAN or DX11 engine using 2 methods:
*NRD* is distributed as a source as well with a “ready-to-use” library (if used in a precompiled form). It can be integrated into any DX12, VULKAN or DX11 engine using two variants:
1. Native implementation of the *NRD* API using engine capabilities
2. Integration via an abstraction layer. In this case, the engine should expose native Graphics API pointers for certain types of objects. The integration layer, provided as a part of SDK, can be used to simplify this kind of integration.

## Build instructions
## BUILD INSTRUCTIONS

### How to build?

- Install [*Cmake*](https://cmake.org/download/) 3.15+
- Install on
Expand All @@ -45,6 +49,31 @@ Supported signal types (modulated irradiance can be used instead of radiance):
- Run `1-Deploy`
- Run `2-Build`

### How to update?

- Clone latest with all dependencies
- Run `4-Clean.bat`
- Re-deploy and build

### How to report IQ issues?

NRD sample has *TESTS* section in the bottom of the UI, a new test can be added if needed. The following procedure is recommended:
- Try to reproduce a problem in the *NRD sample* first
- if reproducible
- add a test (by pressing `Add` button)
- describe the issue and steps to reproduce on *GitHub*
- attach depending on the selected scene `.bin` file from the `Tests` folder
- if not
- verify the integration
- If nothing helps
- describe the issue, attach a video and steps to reproduce

### SDK package generation

- Compile the solution (*Debug* / *Release* or both, depending on what you want to get in *NRD* package)
- Run `3-Prepare NRD SDK`
- Grab generated in the root directory `_NRD_SDK` and `_NRI_SDK` (if needed) folders and use them in your project

### CMake options

- `NRD_DXC_CUSTOM_PATH = "custom/path/to/dxc"` - custom DXC to use if Vulkan SDK is not installed
Expand All @@ -66,15 +95,9 @@ Supported signal types (modulated irradiance can be used instead of radiance):
| Windows | AMD64 | MSVC, Clang |
| Linux | AMD64, ARM64 | GCC, Clang |

### NRD SDK package generation

- Compile the solution (*Debug* / *Release* or both, depending on what you want to get in *NRD* package)
- Run `3-Prepare NRD SDK`
- Grab generated in the root directory `_NRD_SDK` and `_NRI_SDK` (if needed) folders and use them in your project

## INTEGRATION VARIANTS

### Integration Method 1: Black-box library (using the application-side Render Hardware Interface)
### VARIANT 1: Black-box library (using the application-side Render Hardware Interface)

RHI must have the ability to do the following:
* Create shaders from precompiled binary blobs
Expand All @@ -83,7 +106,11 @@ RHI must have the ability to do the following:
* Invoke a Dispatch call (no raster, no VS/PS)
* Create 2D textures with SRV / UAV access

### Integration Method 2: Black-box library (using native API pointers)
### VARIANT 2: White-box library (using the application-side Render Hardware Interface)

Logically it's close to the Method 1, but the integration takes place in the full source code (only the *NRD* project is needed). In this case *NRD* shaders are handled by the application shader compilation pipeline. The application should still use *NRD* via *NRD API* to preserve forward compatibility. This variant suits best for compilation on other platforms (consoles, ARM), unlocks *NRD* modification on the application side and increases portability.

### VARIANT 3: Black-box library (using native API pointers)

If Graphics API's native pointers are retrievable from the RHI, the standard *NRD integration* layer can be used to greatly simplify the integration. In this case, the application should only wrap up native pointers for the *Device*, *CommandList* and some input / output *Resources* into entities, compatible with an API abstraction layer (*[NRI](https://github.com/NVIDIAGameWorks/NRI)*), and all work with *NRD* library will be hidden inside the integration layer:

Expand Down Expand Up @@ -271,21 +298,15 @@ float4 nrdIn = RELAX_FrontEnd_PackRadianceAndHitDist(radiance, hitDistance);
float4 nrdOut = RELAX_BackEnd_UnpackRadiance(nrdOutEncoded);
```

### Integration Method 3: White-box library (using the application-side Render Hardware Interface)

Logically it's close to the Method 1, but the integration takes place in the full source code (only the *NRD* project is needed). In this case *NRD* shaders are handled by the application shader compilation pipeline. The application should still use *NRD* via *NRD API* to preserve forward compatibility. This method suits best for compilation on other platforms (consoles, ARM), unlocks *NRD* modification on the application side and increases portability.

NOTE: this method is WIP. It works, but in the future it will work better out of the box.
## API OVERVIEW

## NRD TERMINOLOGY
### TERMINOLOGY

* *Denoiser method (or method)* - a method for denoising of a particular signal (for example: `Method::DIFFUSE`)
* *Denoiser* - a set of methods aggregated into a monolithic entity (the library is free to rearrange passes without dependencies)
* *Resource* - an input, output or internal resource. Currently can only be a texture
* *Texture pool (or pool)* - a texture pool that stores permanent or transient resources needed for denoising. Textures from the permanent pool are dedicated to *NRD* and can not be reused by the application (history buffers are stored here). Textures from the transient pool can be reused by the application right after denoising. *NRD* doesn’t allocate anything. *NRD* provides resource descriptions, but resource creations are done on the application side.

## NRD API OVERVIEW

### API flow

1. *GetLibraryDesc* - contains general *NRD* library information (supported denoising methods, SPIRV binding offsets). This call can be skipped if this information is known in advance (for example, is diffuse denoiser available?), but it can’t be skipped if SPIRV binding offsets are needed for VULKAN
Expand All @@ -295,15 +316,15 @@ NOTE: this method is WIP. It works, but in the future it will work better out of
5. *GetComputeDispatches* - returns per-dispatch data (bound subresources with required state, constant buffer data)
6. *DestroyDenoiser* - destroys a denoiser

## HOW TO RUN DENOISING?
### HOW TO RUN DENOISING?

*NRD* doesn't make any graphics API calls. The application is supposed to invoke a set of compute *Dispatch* calls to actually denoise input signals. Please, refer to `NrdIntegration::Denoise()` and `NrdIntegration::Dispatch()` calls in `NRDIntegration.hpp` file as an example of an integration using low level RHI.

*NRD* doesn’t have a "resize" functionality. On resolution change the old denoiser needs to be destroyed and a new one needs to be created with new parameters. But *NRD* supports dynamic resolution scaling via `CommonSettings::resolutionScale`.

The following textures can be requested as inputs or outputs for a method. Required resources are specified near a method declaration inside the `Method` enum class. Also `NRD.hlsli` has a comment near each front-end or back-end function, clarifying which resources this function is for.
Some textures can be requested as inputs or outputs for a method (see the next section). Required resources are specified near a method declaration inside the `Method` enum class. Also `NRD.hlsli` has a comment near each front-end or back-end function, clarifying which resources this function is for.

### NRD INPUTS & OUTPUTS
## INPUTS & OUTPUTS

Commons inputs:

Expand Down Expand Up @@ -347,7 +368,7 @@ NRD sample is a good start to familiarize yourself with input requirements and b
- Signal for *NRD* must be separated into diffuse and specular at primary hit
- `hitT` must not include primary hit distance
- Do not pass *sum of lengths of all segments* as `hitT`. A solid baseline is to use hit distance for the 1st bounce only, it works well for diffuse and specular signals
- *NRD sample* uses more complex method for accumulating `hitT` along the path, which takes into account energy dissipation due to lobe spread and curvature at the current hit
- *NRD sample* uses more complex approach for accumulating `hitT` along the path, which takes into account energy dissipation due to lobe spread and curvature at the current hit
- Noise in provided hit distances must follow a diffuse or specular lobe. It implies that `hitT` for `roughness = 0` must be clean (if probabilistic sampling is not in use)
- In case of probabilistic diffuse / specular selection at the primary hit, provided `hitT` must follow the following rules:
- Should not be divided by `PDF`
Expand All @@ -362,9 +383,9 @@ NRD sample is a good start to familiarize yourself with input requirements and b

## VALIDATION LAYER

If `CommonSettings::enableValidation = true` *REBLUR* & *RELAX* denoisers render debug information into `OUT_VALIDATION` output. Alpha channel contains layer transparency to allow easy mix with the final image on the application side.
![Validation](Images/Validation.png)

Currently the following viewport layout is used on the screen:
If `CommonSettings::enableValidation = true` *REBLUR* & *RELAX* denoisers render debug information into `OUT_VALIDATION` output. Alpha channel contains layer transparency to allow easy mix with the final image on the application side. Currently the following viewport layout is used on the screen:

| 0 | 1 | 2 | 3 |
|---|---|---|---|
Expand Down Expand Up @@ -392,6 +413,8 @@ where:
- Viewport 7 - amount of virtual history
- Viewport 8 - number of accumulated frames for diffuse signal (red = `history reset`)
- Viewport 11 - number of accumulated frames for specular signal (red = `history reset`)
- Viewport 12 - input normalized `hitT` for diffuse signal (ambient occlusion, AO)
- Viewport 15 - input normalized `hitT` for specular signal (specular occlusion, SO)

## MEMORY REQUIREMENTS

Expand Down Expand Up @@ -586,16 +609,3 @@ Is this a biased solution? If spatial filtering is off - no, because we just reo
- if shadows overlap, a separate pass is needed to analyze noisy input and classify pixels as *umbra* - *penumbra* (and optionally *empty space*). Raster shadow maps can be used for this if available
- it is not recommended to mix 1 cd and 100000 cd lights, since FP32 texture will be needed for a weighted sum.
In this case, it's better to process the sun and other bright light sources separately.

## HOW TO REPORT ISSUES

NRD sample has *TESTS* section in the bottom of the UI, a new test can be added if needed. The following procedure is recommended:
- Try to reproduce a problem in the *NRD sample* first
- if reproducible
- add a test (by pressing `Add` button)
- describe the issue and steps to reproduce
- attach depending on the selected scene `.bin` file from the `Tests` folder
- if not
- verify the integration
- If nothing helps
- describe the issue, attach a video and steps to reproduce
2 changes: 1 addition & 1 deletion Resources/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Versioning rules:

#define VERSION_MAJOR 3
#define VERSION_MINOR 9
#define VERSION_BUILD 0
#define VERSION_BUILD 1
#define VERSION_REVISION 0

#define VERSION_STRING STR(VERSION_MAJOR.VERSION_MINOR.VERSION_BUILD.VERSION_REVISION)
9 changes: 5 additions & 4 deletions Shaders/Include/REBLUR/REBLUR_Common.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ float GetSmbAccumSpeed( float smbSpecAccumSpeedFactor, float vmbPixelsTraveled,

// Tests 142, 148 and 155 ( or anything with very low roughness and curved surfaces )
float ta = PixelRadiusToWorld( gUnproject, gOrthoMode, vmbPixelsTraveled, viewZ ) / viewZ;
float ca = STL::Math::Sqrt01( 1.0 / ( 1.0 + ta * ta ) );
float ca = STL::Math::Rsqrt( 1.0 + ta * ta );
float angle = STL::Math::AcosApprox( ca );
smbSpecAccumSpeed *= STL::Math::SmoothStep( maxAngle * 1.5, maxAngle * 0.5, angle );
smbSpecAccumSpeed *= STL::Math::SmoothStep( maxAngle, 0.0, angle );

return min( smbSpecAccumSpeed, specAccumSpeed );
}
Expand Down Expand Up @@ -181,9 +181,10 @@ float GetMinAllowedLimitForHitDistNonLinearAccumSpeed( float roughness )

float GetFadeBasedOnAccumulatedFrames( float accumSpeed )
{
float fade = STL::Math::LinearStep( gHistoryFixFrameNum, gHistoryFixFrameNum * 2.0, accumSpeed );
float a = gHistoryFixFrameNum * 2.0 / 3.0 + 1e-6;
float b = gHistoryFixFrameNum * 4.0 / 3.0 + 2e-6;

return fade;
return STL::Math::LinearStep( a, b, accumSpeed );
}

// Misc ( templates )
Expand Down
22 changes: 12 additions & 10 deletions Shaders/Include/REBLUR/REBLUR_DiffuseSpecular_HistoryFix.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :
#endif

// Smooth
float2 frameNum = saturate( frameNumUnclamped / gHistoryFixFrameNum );
float2 c = frameNum;
float invHistoryFixFrameNum = STL::Math::PositiveRcp( gHistoryFixFrameNum );
float2 normFrameNum = saturate( frameNumUnclamped * invHistoryFixFrameNum );
float2 c = normFrameNum;
float2 sum = 1.0;

[unroll]
Expand All @@ -214,15 +215,15 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :

int2 pos = threadPos + int2( i, j );

float2 s = saturate( s_FrameNum[ pos.y ][ pos.x ] / gHistoryFixFrameNum );
float2 s = saturate( s_FrameNum[ pos.y ][ pos.x ] * invHistoryFixFrameNum );
float2 w = step( c, s );

frameNum += s * w;
normFrameNum += s * w;
sum += w;
}
}

frameNum *= rcp( sum );
normFrameNum *= rcp( sum );

// History reconstruction ( tests 20, 23, 24, 27, 28, 54, 59, 65, 66, 76, 81, 98, 112, 117, 124, 126, 128, 134 )
float materialID;
Expand All @@ -234,15 +235,16 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :
float3 Xv = STL::Geometry::ReconstructViewPosition( pixelUv, gFrustum, viewZ, gOrthoMode );
float3 Nv = STL::Geometry::RotateVectorInverse( gViewToWorld, N );

float2 scale = saturate( 1.0 - frameNum );
float2 scale = saturate( 1.0 - normFrameNum ) * float( gHistoryFixFrameNum != 0.0 );
float2 frameNum = normFrameNum * gHistoryFixFrameNum;

#ifdef REBLUR_DIFFUSE
if( scale.x > REBLUR_HISTORY_FIX_THRESHOLD_1 ) // TODO: use REBLUR_HISTORY_FIX_THRESHOLD_2 to switch to 3x3?
{
scale.x = gHistoryFixStrideBetweenSamples / ( 2.0 + frameNum.x * gHistoryFixFrameNum ); // TODO: 2 to match RELAX logic, where HistoryFix uses "1 / ( 1 + "N + 1" )"
scale.x = gHistoryFixStrideBetweenSamples / ( 2.0 + frameNum.x ); // TODO: 2 to match RELAX logic, where HistoryFix uses "1 / ( 1 + "N + 1" )"

// Parameters
float diffNonLinearAccumSpeed = 1.0 / ( 1.0 + frameNumUnclamped.x );
float diffNonLinearAccumSpeed = 1.0 / ( 1.0 + frameNum.x );

float diffNormalWeightParam = GetNormalWeightParams( diffNonLinearAccumSpeed, 1.0 );
float2 diffGeometryWeightParams = GetGeometryWeightParams( gPlaneDistSensitivity, frustumHeight, Xv, Nv, diffNonLinearAccumSpeed );
Expand Down Expand Up @@ -315,7 +317,7 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :
#ifdef REBLUR_SPECULAR
if( scale.y > REBLUR_HISTORY_FIX_THRESHOLD_1 ) // TODO: use REBLUR_HISTORY_FIX_THRESHOLD_2 to switch to 3x3?
{
scale.y = gHistoryFixStrideBetweenSamples / ( 2.0 + frameNum.y * gHistoryFixFrameNum ); // TODO: 2 to match RELAX logic, where HistoryFix uses "1 / ( 1 + "N + 1" )"
scale.y = gHistoryFixStrideBetweenSamples / ( 2.0 + frameNum.y ); // TODO: 2 to match RELAX logic, where HistoryFix uses "1 / ( 1 + "N + 1" )"

// Adjust scale to respect the specular lobe
float hitDistScale = _REBLUR_GetHitDistanceNormalization( viewZ, gHitDistParams, roughness );
Expand All @@ -329,7 +331,7 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :
scale.y = min( scale.y, minBlurRadius / 2.0 );

// Parameters
float specNonLinearAccumSpeed = 1.0 / ( 1.0 + frameNumUnclamped.y );
float specNonLinearAccumSpeed = 1.0 / ( 1.0 + frameNum.y );

float lobeEnergy = lerp( 0.75, 0.85, specNonLinearAccumSpeed );
float lobeHalfAngle = STL::ImportanceSampling::GetSpecularLobeHalfAngle( roughness, lobeEnergy ); // up to 85% energy to depend less on normal weight
Expand Down
Loading

0 comments on commit 8f8ce88

Please sign in to comment.