Skip to content

Commit b520f26

Browse files
committed
NRD updated to v4.11.3:
- PT: hooked up "NRD_MaterialFactors" - PT: improved glass - PT: SHARC usage for specular made lobe-footprint-based instead of "smc"-based - UI: added "Glass" checkbox, transforming some cubes into glass! - added "NRD_RESTORE_INITIAL_STATE" switch - added CPU-side performance markers - better stated geometry flags - NRI updated to v1.158 - updated deps - updated tests
1 parent 1055e49 commit b520f26

File tree

11 files changed

+110
-85
lines changed

11 files changed

+110
-85
lines changed

External/NRD

Submodule NRD updated from 000f9c7 to 073fe93

External/NRIFramework

Shaders/Composition.cs.hlsl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,19 @@ void main( int2 pixelPos : SV_DispatchThreadId )
197197
spec.xyz *= gIndirectSpecular;
198198

199199
// Material modulation ( convert radiance back into irradiance )
200-
float NoV = abs( dot( N, V ) );
201-
float3 Fenv = BRDF::EnvironmentTerm_Rtg( Rf0, NoV, roughness );
202-
float3 diffDemod = ( 1.0 - Fenv ) * albedo * 0.99 + 0.01;
203-
float3 specDemod = Fenv * 0.99 + 0.01;
200+
float3 diffFactor, specFactor;
201+
NRD_MaterialFactors( N, V, albedo, Rf0, roughness, diffFactor, specFactor );
204202

203+
// We can combine radiance ( for everything ) and irradiance ( for hair ) in denoising if material ID test is enabled
205204
if( materialID == MATERIAL_ID_HAIR )
206205
{
207-
diffDemod = 1.0;
208-
specDemod = 1.0;
206+
diffFactor = 1.0;
207+
specFactor = 1.0;
209208
}
210209

211210
// Composition
212-
float3 Ldiff = diff.xyz * diffDemod;
213-
float3 Lspec = spec.xyz * specDemod;
211+
float3 Ldiff = diff.xyz * diffFactor;
212+
float3 Lspec = spec.xyz * specFactor;
214213

215214
// Apply PSR throughput ( primary surface material before replacement )
216215
#if( USE_PSR == 1 )

Shaders/Include/RaytracingShared.hlsli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ bool IsPsrAllowed( MaterialProps materialProps )
527527

528528
float3 GetShadowedLighting( GeometryProps geometryProps, MaterialProps materialProps, bool softShadows = true )
529529
{
530-
const uint instanceInclusionMask = GEOMETRY_IGNORE_TRANSPARENT; // Default shadow rays must ignore transparency // TODO: what about translucency?
530+
const uint instanceInclusionMask = FLAG_NON_TRANSPARENT; // Default shadow rays must ignore transparency // TODO: what about translucency?
531531
const uint rayFlags = 0;
532532

533533
float3 L = materialProps.Ldirect;

Shaders/Include/Shared.hlsli

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.
120120
#define PT_GLASS_RAY_OFFSET 0.05 // pixels
121121
#define PT_MAX_FIREFLY_RELATIVE_INTENSITY 20.0 // no more than 20x energy increase in case of probabilistic sampling
122122
#define PT_EVIL_TWIN_LOBE_TOLERANCE 0.005 // normalized %
123+
#define PT_GLASS_MIN_F 0.05 // adds a bit of stability and bias
123124

124125
// Spatial HAsh-ased Radiance Cache
125126
#define SHARC_CAPACITY ( 1 << 22 )
@@ -161,17 +162,15 @@ license agreement from NVIDIA CORPORATION is strictly prohibited.
161162
#define FLAG_FIRST_BIT 25 // this + number of flags must be <= 32
162163
#define NON_FLAG_MASK ( ( 1 << FLAG_FIRST_BIT ) - 1 )
163164

164-
#define FLAG_DEFAULT 0x01 // always set
165-
#define FLAG_TRANSPARENT 0x02 // transparent
165+
#define FLAG_NON_TRANSPARENT 0x01 // geometry flag: non-transparent
166+
#define FLAG_TRANSPARENT 0x02 // geometry flag: transparent
166167
#define FLAG_FORCED_EMISSION 0x04 // animated emissive cube
167168
#define FLAG_STATIC 0x08 // no velocity
168169
#define FLAG_DEFORMABLE 0x10 // local animation
169170
#define FLAG_HAIR 0x20 // hair
170171
#define FLAG_LEAF 0x40 // leaf
171172

172-
#define GEOMETRY_ALL 0xFF
173-
#define GEOMETRY_ONLY_TRANSPARENT ( FLAG_TRANSPARENT )
174-
#define GEOMETRY_IGNORE_TRANSPARENT ( ~FLAG_TRANSPARENT )
173+
#define GEOMETRY_ALL ( FLAG_NON_TRANSPARENT | FLAG_TRANSPARENT )
175174

176175
//===============================================================
177176
// STRUCTS
@@ -293,7 +292,6 @@ NRI_RESOURCE( cbuffer, GlobalConstants, b, 0, SET_GLOBAL )
293292
float gExposure;
294293
float gMipBias;
295294
float gOrthoMode;
296-
uint32_t gTransparent;
297295
uint32_t gSharcMaxAccumulatedFrameNum;
298296
uint32_t gDenoiserType;
299297
uint32_t gDisableShadowsAndEnableImportanceSampling; // TODO: remove - modify GetSunIntensity to return 0 if sun is below horizon

Shaders/SharcUpdate.cs.hlsl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void main( uint2 pixelPos : SV_DispatchThreadId )
8080
cameraRayDirection = normalize( Rng::Hash::GetFloat4( ).xyz - 0.5 );
8181

8282
// Cast ray
83-
GeometryProps geometryProps = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, INF, GetConeAngleFromAngularRadius( 0.0, gTanPixelAngularRadius * SHARC_DOWNSCALE ), gWorldTlas, GEOMETRY_IGNORE_TRANSPARENT, 0 );
83+
GeometryProps geometryProps = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, INF, GetConeAngleFromAngularRadius( 0.0, gTanPixelAngularRadius * SHARC_DOWNSCALE ), gWorldTlas, FLAG_NON_TRANSPARENT, 0 );
8484
MaterialProps materialProps = GetMaterialProps( geometryProps, USE_SHARC_V_DEPENDENT == 0 );
8585

8686
if( geometryProps.IsSky( ) )
@@ -164,7 +164,7 @@ void main( uint2 pixelPos : SV_DispatchThreadId )
164164
// 1. If IS enabled, check the ray in LightBVH
165165
bool isMiss = false;
166166
if( gDisableShadowsAndEnableImportanceSampling && maxSamplesNum != 1 )
167-
isMiss = CastVisibilityRay_AnyHit( geometryProps.GetXoffset( geometryProps.N ), r, 0.0, INF, mipAndCone, gLightTlas, GEOMETRY_ALL, 0 );
167+
isMiss = CastVisibilityRay_AnyHit( geometryProps.GetXoffset( geometryProps.N ), r, 0.0, INF, mipAndCone, gLightTlas, FLAG_NON_TRANSPARENT, 0 );
168168

169169
// 2. Count rays hitting emissive surfaces
170170
if( !isMiss )
@@ -242,7 +242,7 @@ void main( uint2 pixelPos : SV_DispatchThreadId )
242242
// Trace to the next hit
243243
//=========================================================================================================================================================
244244

245-
geometryProps = CastRay( geometryProps.GetXoffset( geometryProps.N ), ray, 0.0, INF, mipAndCone, gWorldTlas, GEOMETRY_IGNORE_TRANSPARENT, 0 );
245+
geometryProps = CastRay( geometryProps.GetXoffset( geometryProps.N ), ray, 0.0, INF, mipAndCone, gWorldTlas, FLAG_NON_TRANSPARENT, 0 );
246246
materialProps = GetMaterialProps( geometryProps, USE_SHARC_V_DEPENDENT == 0 );
247247
}
248248

Shaders/TraceOpaque.cs.hlsl

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ float2 GetBlueNoise( uint2 pixelPos, bool isCheckerboard, uint seed = 0 )
5858
blue += ( dither.xyxy - 0.5 ) * ( 1.0 / 256.0 );
5959

6060
// Don't use blue noise in these cases
61+
[flatten]
6162
if( gDenoiserType == DENOISER_REFERENCE || gRR )
6263
blue.xy = Rng::Hash::GetFloat2( );
6364

@@ -259,8 +260,8 @@ TraceOpaqueResult TraceOpaque( inout TraceOpaqueDesc desc )
259260
sharcState.voxelDataBuffer = gInOut_SharcVoxelDataBuffer;
260261

261262
bool isSharcAllowed = gSHARC && NRD_MODE < OCCLUSION; // trivial
262-
isSharcAllowed &= geometryProps.hitT > voxelSize; // voxel angular size is acceptable
263263
isSharcAllowed &= Rng::Hash::GetFloat( ) > Lpsr.w; // probabilistically estimate the need
264+
isSharcAllowed &= geometryProps.hitT > voxelSize; // voxel angular size is acceptable
264265
isSharcAllowed &= desc.bounceNum == 0; // allow only for the last bounce for PSR
265266

266267
float3 sharcRadiance;
@@ -358,7 +359,7 @@ TraceOpaqueResult TraceOpaque( inout TraceOpaqueDesc desc )
358359
// Diffuse or specular path?
359360
if( gTracingMode == RESOLUTION_FULL_PROBABILISTIC || bounce > 1 )
360361
{
361-
isDiffuse = rnd < diffuseProbability;
362+
isDiffuse = rnd < diffuseProbability; // TODO: if "diffuseProbability" is clamped, "pathThroughput" should be adjusted too
362363
pathThroughput /= abs( float( !isDiffuse ) - diffuseProbability );
363364

364365
if( bounce == 1 )
@@ -437,7 +438,7 @@ TraceOpaqueResult TraceOpaque( inout TraceOpaqueDesc desc )
437438
// 1. If IS enabled, check the ray in LightBVH
438439
bool isMiss = false;
439440
if( gDisableShadowsAndEnableImportanceSampling && maxSamplesNum != 1 )
440-
isMiss = CastVisibilityRay_AnyHit( geometryProps.GetXoffset( geometryProps.N ), r, 0.0, INF, mipAndCone, gLightTlas, GEOMETRY_ALL, desc.rayFlags );
441+
isMiss = CastVisibilityRay_AnyHit( geometryProps.GetXoffset( geometryProps.N ), r, 0.0, INF, mipAndCone, gLightTlas, FLAG_NON_TRANSPARENT, desc.rayFlags );
441442

442443
// 2. Count rays hitting emissive surfaces
443444
if( !isMiss )
@@ -609,10 +610,10 @@ TraceOpaqueResult TraceOpaque( inout TraceOpaqueDesc desc )
609610
sharcState.hashMapData.hashEntriesBuffer = gInOut_SharcHashEntriesBuffer;
610611
sharcState.voxelDataBuffer = gInOut_SharcVoxelDataBuffer;
611612

613+
float footprint = geometryProps.hitT * ImportanceSampling::GetSpecularLobeTanHalfAngle( ( isDiffuse || bounce == desc.bounceNum ) ? 1.0 : materialProps.roughness, 0.5 );
612614
bool isSharcAllowed = gSHARC && NRD_MODE < OCCLUSION; // trivial
613-
isSharcAllowed &= geometryProps.hitT > voxelSize; // voxel angular size is acceptable
614615
isSharcAllowed &= Rng::Hash::GetFloat( ) > Lcached.w; // probabilistically estimate the need
615-
isSharcAllowed &= isDiffuse || Rng::Hash::GetFloat( ) < smc || bounce == desc.bounceNum; // allowed for diffuse-like events or last bounce
616+
isSharcAllowed &= footprint > voxelSize; // voxel angular size is acceptable
616617

617618
float3 sharcRadiance;
618619
if( isSharcAllowed && SharcGetCachedRadiance( sharcState, sharcHitData, sharcRadiance, false ) )
@@ -698,26 +699,25 @@ TraceOpaqueResult TraceOpaque( inout TraceOpaqueDesc desc )
698699
}
699700
}
700701

701-
// Material de-modulation ( convert irradiance into radiance )
702-
float3 albedo, Rf0;
703-
BRDF::ConvertBaseColorMetalnessToAlbedoRf0( desc.materialProps.baseColor, desc.materialProps.metalness, albedo, Rf0 );
702+
{ // Material de-modulation ( convert irradiance into radiance )
703+
float3 albedo, Rf0;
704+
BRDF::ConvertBaseColorMetalnessToAlbedoRf0( desc.materialProps.baseColor, desc.materialProps.metalness, albedo, Rf0 );
704705

705-
float NoV = abs( dot( desc.materialProps.N, desc.geometryProps.V ) );
706-
float3 Fenv = BRDF::EnvironmentTerm_Rtg( Rf0, NoV, desc.materialProps.roughness );
707-
float3 diffDemod = ( 1.0 - Fenv ) * albedo * 0.99 + 0.01;
708-
float3 specDemod = Fenv * 0.99 + 0.01;
706+
float3 diffFactor, specFactor;
707+
NRD_MaterialFactors( desc.materialProps.N, desc.geometryProps.V, albedo, Rf0, desc.materialProps.roughness, diffFactor, specFactor );
709708

710-
// We can combine radiance ( for everything ) and irradiance ( for hair ) in denoising if material ID test is enabled
711-
if( desc.geometryProps.Has( FLAG_HAIR ) && NRD_NORMAL_ENCODING == NRD_NORMAL_ENCODING_R10G10B10A2_UNORM )
712-
{
713-
diffDemod = 1.0;
714-
specDemod = 1.0;
715-
}
709+
// We can combine radiance ( for everything ) and irradiance ( for hair ) in denoising if material ID test is enabled
710+
if( desc.geometryProps.Has( FLAG_HAIR ) && NRD_NORMAL_ENCODING == NRD_NORMAL_ENCODING_R10G10B10A2_UNORM )
711+
{
712+
diffFactor = 1.0;
713+
specFactor = 1.0;
714+
}
716715

717-
if( gOnScreen != SHOW_MIP_SPECULAR )
718-
{
719-
result.diffRadiance /= diffDemod;
720-
result.specRadiance /= specDemod;
716+
if( gOnScreen != SHOW_MIP_SPECULAR )
717+
{
718+
result.diffRadiance /= diffFactor;
719+
result.specRadiance /= specFactor;
720+
}
721721
}
722722

723723
// Radiance is already divided by sampling probability, we need to average across all paths
@@ -817,7 +817,7 @@ void main( uint2 pixelPos : SV_DispatchThreadId )
817817
float3 cameraRayDirection = ( float3 )0;
818818
GetCameraRay( cameraRayOrigin, cameraRayDirection, sampleUv );
819819

820-
GeometryProps geometryProps0 = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, INF, GetConeAngleFromRoughness( 0.0, 0.0 ), gWorldTlas, ( gOnScreen == SHOW_INSTANCE_INDEX || gOnScreen == SHOW_NORMAL ) ? GEOMETRY_ALL : GEOMETRY_IGNORE_TRANSPARENT, 0 );
820+
GeometryProps geometryProps0 = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, INF, GetConeAngleFromRoughness( 0.0, 0.0 ), gWorldTlas, ( gOnScreen == SHOW_INSTANCE_INDEX || gOnScreen == SHOW_NORMAL ) ? GEOMETRY_ALL : FLAG_NON_TRANSPARENT, 0 );
821821
MaterialProps materialProps0 = GetMaterialProps( geometryProps0 );
822822

823823
// ViewZ
@@ -909,8 +909,8 @@ void main( uint2 pixelPos : SV_DispatchThreadId )
909909
desc.pixelPos = pixelPos;
910910
desc.checkerboard = checkerboard;
911911
desc.pathNum = gSampleNum;
912-
desc.bounceNum = gBounceNum; // TODO: adjust by roughness?
913-
desc.instanceInclusionMask = GEOMETRY_IGNORE_TRANSPARENT;
912+
desc.bounceNum = gBounceNum;
913+
desc.instanceInclusionMask = FLAG_NON_TRANSPARENT;
914914
desc.rayFlags = 0;
915915

916916
TraceOpaqueResult result = TraceOpaque( desc );

Shaders/TraceTransparent.cs.hlsl

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ float3 TraceTransparent( TraceTransparentDesc desc )
5454
GeometryProps geometryProps = desc.geometryProps;
5555
float pathThroughput = 1.0;
5656
bool isReflection = desc.isReflection;
57+
float bayer = Sequence::Bayer4x4( desc.pixelPos, gFrameIndex );
5758

5859
[loop]
5960
for( uint bounce = 1; bounce <= desc.bounceNum; bounce++ ) // TODO: stop if pathThroughput is low
@@ -66,11 +67,22 @@ float3 TraceTransparent( TraceTransparentDesc desc )
6667
pathThroughput *= isReflection ? F : 1.0 - F;
6768
else
6869
{
69-
float rndBayer = Sequence::Bayer4x4( desc.pixelPos, gFrameIndex + bounce );
70-
float rndWhite = Rng::Hash::GetFloat( );
71-
float rnd = ( gDenoiserType == DENOISER_REFERENCE || gRR ) ? rndWhite : rndBayer + rndWhite / 16.0;
72-
73-
isReflection = rnd < F;
70+
float rnd = frac( bayer + Sequence::Halton( bounce, 3 ) ); // "Halton( bounce, 2 )" works worse than others
71+
72+
// Bonus dithering to break banding // TODO: needed for "transparent machines"
73+
/*
74+
float ditherMask = Sequence::Bayer4x4( desc.pixelPos, bounce ); // or
75+
//float ditherMask = Rng::Hash::GetFloat( ); // or
76+
rnd = saturate( rnd + ( ditherMask - 0.5 ) * 0.04 );
77+
*/
78+
79+
[flatten]
80+
if( gDenoiserType == DENOISER_REFERENCE || gRR )
81+
rnd = Rng::Hash::GetFloat( );
82+
else
83+
F = clamp( F, PT_GLASS_MIN_F, 1.0 - PT_GLASS_MIN_F ); // TODO: needed?
84+
85+
isReflection = rnd < F; // TODO: if "F" is clamped, "pathThroughput" should be adjusted too
7486
}
7587

7688
// Compute ray
@@ -79,25 +91,23 @@ float3 TraceTransparent( TraceTransparentDesc desc )
7991
{
8092
float3 I = -geometryProps.V;
8193
float NoI = dot( geometryProps.N, I );
82-
float k = 1.0 - eta * eta * ( 1.0 - NoI * NoI );
83-
84-
if( k < 0.0 )
85-
return 0.0; // should't be here
94+
float k = max( 1.0 - eta * eta * ( 1.0 - NoI * NoI ), 0.0 );
8695

8796
ray = normalize( eta * I - ( eta * NoI + sqrt( k ) ) * geometryProps.N );
8897
eta = 1.0 / eta;
8998
}
9099

91100
// Trace
92101
float3 Xoffset = geometryProps.GetXoffset( geometryProps.N * Math::Sign( dot( ray, geometryProps.N ) ), PT_GLASS_RAY_OFFSET );
93-
uint flags = bounce == desc.bounceNum ? GEOMETRY_IGNORE_TRANSPARENT : GEOMETRY_ALL;
102+
uint flags = bounce == desc.bounceNum ? FLAG_NON_TRANSPARENT : GEOMETRY_ALL;
94103

95104
geometryProps = CastRay( Xoffset, ray, 0.0, INF, GetConeAngleFromRoughness( geometryProps.mip, 0.0 ), gWorldTlas, flags, 0 );
96105

97-
// TODO: glass internal extinction?
98-
// ideally each "medium" should have "eta" and "extinction" parameters in "TraceTransparentDesc" and "TraceOpaqueDesc"
99-
if( !isReflection )
100-
pathThroughput *= 0.96;
106+
// TODO: ideally each "medium" should have "eta" and "extinction" parameters in "TraceTransparentDesc" and "TraceOpaqueDesc"
107+
bool isAir = eta < 1.0;
108+
float extinction = isAir ? 0.0 : 1.0; // TODO: tint color? // TODO: 0.01 for "transparent machines"
109+
if( !geometryProps.IsSky() ) // TODO: fix for non-convex geometry
110+
pathThroughput *= exp( -extinction * geometryProps.hitT );
101111

102112
// Is opaque hit found?
103113
if( !geometryProps.Has( FLAG_TRANSPARENT ) )
@@ -140,8 +150,8 @@ float3 TraceTransparent( TraceTransparentDesc desc )
140150
sharcState.voxelDataBuffer = gInOut_SharcVoxelDataBuffer;
141151

142152
bool isSharcAllowed = gSHARC && NRD_MODE < OCCLUSION; // trivial
143-
isSharcAllowed &= geometryProps.hitT > voxelSize; // voxel angular size is acceptable
144153
isSharcAllowed &= Rng::Hash::GetFloat( ) > Lcached.w; // probabilistically estimate the need
154+
isSharcAllowed &= geometryProps.hitT > voxelSize; // voxel angular size is acceptable // TODO: can be skipped to get flat ambient in some cases
145155

146156
float3 sharcRadiance;
147157
if( isSharcAllowed && SharcGetCachedRadiance( sharcState, sharcHitData, sharcRadiance, false ) )
@@ -197,10 +207,10 @@ void main( int2 pixelPos : SV_DispatchThreadId )
197207
float3 Xv = Geometry::ReconstructViewPosition( sampleUv, gCameraFrustum, viewZ, gOrthoMode );
198208
float tmin0 = gOrthoMode == 0 ? length( Xv ) : abs( Xv.z );
199209

200-
GeometryProps geometryPropsT = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, tmin0, GetConeAngleFromRoughness( 0.0, 0.0 ), gWorldTlas, gTransparent ? GEOMETRY_ONLY_TRANSPARENT : 0, 0 );
210+
GeometryProps geometryPropsT = CastRay( cameraRayOrigin, cameraRayDirection, 0.0, tmin0, GetConeAngleFromRoughness( 0.0, 0.0 ), gWorldTlas, FLAG_TRANSPARENT, 0 );
201211

202212
// Trace delta events
203-
if( !geometryPropsT.IsSky( ) && geometryPropsT.hitT < tmin0 )
213+
if( !geometryPropsT.IsSky( ) && geometryPropsT.hitT < tmin0 && gOnScreen == SHOW_FINAL )
204214
{
205215
// Append "glass" mask to "hair" mask
206216
viewZAndTaaMask = viewZAndTaaMask < 0.0 ? viewZAndTaaMask : -viewZAndTaaMask;

0 commit comments

Comments
 (0)