Skip to content

Commit

Permalink
v4.9.2:
Browse files Browse the repository at this point in the history
HIGHLIGHTS:
- improvements and bug fixes

BREAKING CHANGE:
- "MemoryAllocatorInterface" renamed to "AllocationCallbacks"

DETAILS:
- NRD: fixed "NRD_STATIC_LIBRARY"
- REBLUR: improved MV patching (if enabled)
- updated docs
  • Loading branch information
dzhdanNV committed Aug 23, 2024
1 parent 7e36d4b commit a3ae12b
Show file tree
Hide file tree
Showing 12 changed files with 40 additions and 33 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ file (GLOB GLOB_RESOURCES "Resources/*")
source_group ("Resources" FILES ${GLOB_RESOURCES})

if (NRD_STATIC_LIBRARY)
set (COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS} NRD_STATIC_LIBRARY)
add_library (${PROJECT_NAME} STATIC ${GLOB_SOURCE} ${GLOB_DENOISERS} ${ML_FILES} ${GLOB_RESOURCES} ${GLOB_INCUDE})
else ()
add_library (${PROJECT_NAME} SHARED ${GLOB_SOURCE} ${GLOB_DENOISERS} ${ML_FILES} ${GLOB_RESOURCES} ${GLOB_INCUDE})
Expand Down
2 changes: 1 addition & 1 deletion External/MathLib
6 changes: 3 additions & 3 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 4
#define NRD_VERSION_MINOR 9
#define NRD_VERSION_BUILD 1
#define NRD_VERSION_DATE "14 August 2024"
#define NRD_VERSION_BUILD 2
#define NRD_VERSION_DATE "23 August 2024"

#if defined(_MSC_VER)
#define NRD_CALL __fastcall
Expand All @@ -41,7 +41,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.
#endif

#ifndef NRD_API
#if NRD_STATIC_LIBRARY
#ifdef NRD_STATIC_LIBRARY
#define NRD_API
#else
#define NRD_API extern "C"
Expand Down
4 changes: 2 additions & 2 deletions Include/NRDDescs.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ namespace nrd
MAX_NUM
};

struct MemoryAllocatorInterface
struct AllocationCallbacks
{
void* (*Allocate)(void* userArg, size_t size, size_t alignment);
void* (*Reallocate)(void* userArg, void* memory, size_t size, size_t alignment);
Expand Down Expand Up @@ -409,7 +409,7 @@ namespace nrd

struct InstanceCreationDesc
{
MemoryAllocatorInterface memoryAllocatorInterface;
AllocationCallbacks allocationCallbacks;
const DenoiserDesc* denoisers;
uint32_t denoisersNum;
};
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# NVIDIA REAL-TIME DENOISERS v4.9.1 (NRD)
# NVIDIA REAL-TIME DENOISERS v4.9.2 (NRD)

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

Expand Down Expand Up @@ -632,17 +632,20 @@ When denoising reflections in pure mirrors, some advantages can be reached if *N
Notes, requirements and restrictions:
- the primary hit (0th bounce) gets replaced with the first "non-pure mirror" hit in the bounce chain - this hit becomes *PSR*
- all associated data in the g-buffer gets replaced by *PSR* data
- the camera "sees" PSRs like the mirror surfaces in-between don't exist. This space is called virtual world space
- virtual space position lies on the same view vector as the primary hit position, but the position is elongated. Elongation depends on `hitT` and curvature at bounces, starting from the primary hit
- the camera "sees" PSR like the mirror surface in-between don't exist. This space is called virtual world space
- virtual space position lies on the same view vector as the primary hit position, but the position is elongated. Elongation depends on `hitT` and curvature at hits, starting from the primary hit
- virtual space normal is the normal at *PSR* hit mirrored several times in the reversed order until the primary hit is reached
- *PSR* data is NOT always data at the *PSR* hit!
- material properties (albedo, metalness, roughness etc.) are from *PSR* hit
- `IN_VIEWZ` contains `viewZ` of the virtual position
- `IN_MV` contains motion of the virtual position
- `IN_NORMAL_ROUGHNESS` contains normal at virtual world space and roughness at *PSR*
- accumulated `hitT` for *NRD* starts at the *PSR* hit. Curvature must be taken into account on the application side only for 2nd+ bounces starting from this hit (similarly to `hitT` requirements in *Noisy Inputs* section)
- `IN_VIEWZ` contains `viewZ` of the virtual position, potentially adjusted several times by curvature at hits
- `IN_MV` contains motion of the virtual position, potentially adjusted several times by curvature at hits
- accumulated `hitT` starts at the *PSR* hit, potentially adjusted several times by curvature at hits
- curvature should be taken into account starting from the 1st bounce, because the primary surface normal will be replaced by *PSR* normal, i.e. the former will be unreachable on the *NRD* side
- ray direction for *NRD* must be transformed into virtual space

IMPORTANT: in other words, *PSR* is perfect for flat mirrors. *PSR* on curved surfaces works even without respecting curvature, but reprojection artefacts can appear.

In case of *PSR* *NRD* disocclusion logic doesn't take curvature at primary hit into account, because data for primary hits is replaced. This can lead to more intense disocclusions on bumpy surfaces due to significant ray divergence. To mitigate this problem 2x-10x larger `disocclusionThreshold` can be used. This is an applicable solution if the denoiser is used to denoise surfaces with *PSR* only (glass only, for example). In a general case, when *PSR* and normal surfaces are mixed on the screen, higher disocclusion thresholds are needed only for pixels with *PSR*. This can be achieved by using `IN_DISOCCLUSION_THRESHOLD_MIX` input to smoothly mix baseline `disocclusionThreshold` into bigger `disocclusionThresholdAlternate` from `CommonSettings`. Most likely the increased disocclusion threshold is needed only for pixels with normal details at primary hits (local curvature is not zero).

The illustration below shows expected inputs for secondary hits:
Expand Down
2 changes: 1 addition & 1 deletion Resources/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ Versioning rules:

#define VERSION_MAJOR 4
#define VERSION_MINOR 9
#define VERSION_BUILD 1
#define VERSION_BUILD 2

#define VERSION_STRING STR(VERSION_MAJOR.VERSION_MINOR.VERSION_BUILD encoding=NRD_NORMAL_ENCODING.NRD_ROUGHNESS_ENCODING)
4 changes: 2 additions & 2 deletions Shaders/Include/REBLUR_Config.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.
#define REBLUR_BLUR_FRACTION_SCALE 1.0

#define REBLUR_POST_BLUR_ROTATOR_MODE NRD_FRAME
#define REBLUR_POST_BLUR_FRACTION_SCALE 0.5
#define REBLUR_POST_BLUR_RADIUS_SCALE 2.0
#define REBLUR_POST_BLUR_FRACTION_SCALE 0.5 // TODO: adjust based on sum of non-noisy data based weights...
#define REBLUR_POST_BLUR_RADIUS_SCALE 2.0 // ... ( normalized to number of taps ) from the blur pass?

#define REBLUR_HIT_DIST_MIN_WEIGHT( smc ) ( 0.1 * smc ) // was 0.1

Expand Down
16 changes: 9 additions & 7 deletions Shaders/Include/REBLUR_TemporalStabilization.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,15 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :

float3 Fenv = BRDF::EnvironmentTerm_Rtg( Rf0, NoV, roughness );

float lumSpec = Color::Luminance( Fenv ) * virtualHistoryAmount; // TODO: review
float lumSpec = Color::Luminance( Fenv );
float lumDiff = Color::Luminance( albedo * ( 1.0 - Fenv ) );
float specProb = lumSpec / ( lumDiff + lumSpec + NRD_EPS );

Rng::Hash::Initialize( pixelPos, gFrameIndex );
float f = Math::SmoothStep( gSpecProbabilityThresholdsForMvModification.x, gSpecProbabilityThresholdsForMvModification.y, specProb );
if( Rng::Hash::GetFloat( ) < f )
f *= 1.0 - GetSpecMagicCurve( roughness );
f *= 1.0 - Math::Sqrt01( abs( curvature ) );

if( f != 0.0 )
{
float3 specMv = Xvirtual - X; // world-space delta fits badly into FP16! Prefer 2.5D motion!
if( gMvScale.w == 0.0 )
Expand All @@ -330,11 +332,11 @@ NRD_EXPORT void NRD_CS_MAIN( int2 threadPos : SV_GroupThreadId, int2 pixelPos :
specMv.z = Geometry::AffineTransform( gWorldToViewPrev, Xvirtual ).z - viewZ; // TODO: is it useful?
}

mv = specMv;

// Modify only .xy for 2D and .xyz for 2.5D and 3D MVs
inMv.xy = mv.xy / gMvScale.xy;
inMv.z = gMvScale.z == 0.0 ? inMv.z : mv.z / gMvScale.z;
mv.xy = specMv.xy / gMvScale.xy;
mv.z = gMvScale.z == 0.0 ? inMv.z : specMv.z / gMvScale.z;

inMv.xyz = lerp( inMv.xyz, mv, f );

gInOut_Mv[ WithRectOrigin( pixelPos ) ] = inMv;
}
Expand Down
2 changes: 1 addition & 1 deletion Source/InstanceImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.

#include "NRD.h"

typedef nrd::MemoryAllocatorInterface MemoryAllocatorInterface;
typedef nrd::AllocationCallbacks AllocationCallbacks;
#include "StdAllocator.h"

#include "Timer.h"
Expand Down
16 changes: 8 additions & 8 deletions Source/StdAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ inline void AlignedFree(void* userArg, void* memory)

#endif

inline void CheckAndSetDefaultAllocator(MemoryAllocatorInterface& memoryAllocatorInterface)
inline void CheckAndSetDefaultAllocator(AllocationCallbacks& allocationCallbacks)
{
if (memoryAllocatorInterface.Allocate != nullptr)
if (allocationCallbacks.Allocate != nullptr)
return;

memoryAllocatorInterface.Allocate = AlignedMalloc;
memoryAllocatorInterface.Reallocate = AlignedRealloc;
memoryAllocatorInterface.Free = AlignedFree;
allocationCallbacks.Allocate = AlignedMalloc;
allocationCallbacks.Reallocate = AlignedRealloc;
allocationCallbacks.Free = AlignedFree;
}

template<typename T>
Expand All @@ -121,7 +121,7 @@ struct StdAllocator
typedef std::true_type propagate_on_container_move_assignment;
typedef std::false_type is_always_equal;

StdAllocator(const MemoryAllocatorInterface& memoryAllocatorInterface) : m_Interface(memoryAllocatorInterface)
StdAllocator(const AllocationCallbacks& allocationCallbacks) : m_Interface(allocationCallbacks)
{ CheckAndSetDefaultAllocator(m_Interface); }

StdAllocator(const StdAllocator<T>& allocator) : m_Interface(allocator.GetInterface())
Expand All @@ -143,14 +143,14 @@ struct StdAllocator
void deallocate(T* memory, size_t) noexcept
{ m_Interface.Free(m_Interface.userArg, memory); }

const MemoryAllocatorInterface& GetInterface() const
const AllocationCallbacks& GetInterface() const
{ return m_Interface; }

template<typename U>
using other = StdAllocator<U>;

private:
MemoryAllocatorInterface m_Interface = {};
AllocationCallbacks m_Interface = {};
};

template<typename T>
Expand Down
4 changes: 2 additions & 2 deletions Source/Wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ NRD_API nrd::Result NRD_CALL nrd::CreateInstance(const InstanceCreationDesc& ins
#endif

InstanceCreationDesc modifiedInstanceCreationDesc = instanceCreationDesc;
CheckAndSetDefaultAllocator(modifiedInstanceCreationDesc.memoryAllocatorInterface);
CheckAndSetDefaultAllocator(modifiedInstanceCreationDesc.allocationCallbacks);

StdAllocator<uint8_t> memoryAllocator(modifiedInstanceCreationDesc.memoryAllocatorInterface);
StdAllocator<uint8_t> memoryAllocator(modifiedInstanceCreationDesc.allocationCallbacks);

InstanceImpl* implementation = Allocate<InstanceImpl>(memoryAllocator, memoryAllocator);
const Result result = implementation->Create(modifiedInstanceCreationDesc);
Expand Down
1 change: 1 addition & 0 deletions UPDATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ A single NRD instance can now include any combination of denoisers, including re

- *API*:
- exposed `ReblurSettings::hitDistanceStabilizationStrength` allowing to control the responsiviness of ambient and specular occlusion in the temporal stabilization pass and reach parity with `REBLUR_OCCLUSION` if set to `0`
- `MemoryAllocatorInterface` renamed to `AllocationCallbacks`
- exposed `CommonSettings::strandMaterialID`, enabling "under-the-hood" tweaks for hair (and grass) denoising
- exposed `CommonSettings::strandThickness`, defining how NRD adapts to sub-pixel thick details. It works in conjunction with `CommonSettings::disocclusionThresholdAlternate` for `CommonSettings::strandMaterialID` without a need to provide `IN_DISOCCLUSION_THRESHOLD_MIX` texture
- *REBLUR*:
Expand Down

0 comments on commit a3ae12b

Please sign in to comment.