mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-19 04:04:54 +02:00
Added denoising.
This commit is contained in:
@@ -3398,9 +3398,19 @@ float EstimateSpecularRoughness(float3 specularAlbedo)
|
||||
{
|
||||
// No roughness map is available in this G-buffer path, so infer a stable
|
||||
// perceptual roughness from the specular map strength. Brighter spec maps
|
||||
// get tighter highlights; dark/missing maps stay broad and subdued.
|
||||
// get tighter highlights, but keep a floor high enough that POM/normal-map
|
||||
// detail cannot collapse into one-pixel GGX fireflies.
|
||||
float peak = SpecularPeak3(saturate(specularAlbedo));
|
||||
return clamp(lerp(0.68, 0.34, peak), 0.28, 0.72);
|
||||
return clamp(lerp(0.70, 0.42, peak), 0.38, 0.74);
|
||||
}
|
||||
|
||||
float3 LimitSpecularPeak(float3 c, float peakLimit)
|
||||
{
|
||||
c = max(c, 0.0);
|
||||
float peak = SpecularPeak3(c);
|
||||
if (peak > peakLimit && peak > 1.0e-5)
|
||||
c *= peakLimit / peak;
|
||||
return c;
|
||||
}
|
||||
|
||||
float3 ComputeSpecular(
|
||||
@@ -3463,7 +3473,7 @@ float3 ComputeSpecular(
|
||||
float3 F = F0 + (1.0 - F0) * pow(1.0 - VoH, 5.0);
|
||||
|
||||
float specTerm = (D * G) / max(4.0 * NoL * NoV, 1.0e-4);
|
||||
specTerm = min(specTerm, 5.0);
|
||||
specTerm = min(specTerm, 3.0);
|
||||
|
||||
const float SPECULAR_ENERGY_SCALE = 2.35;
|
||||
|
||||
@@ -3477,7 +3487,7 @@ float3 ComputeSpecular(
|
||||
specTerm *
|
||||
SPECULAR_ENERGY_SCALE;
|
||||
|
||||
return clamp(specular, 0.0, 8.0);
|
||||
return LimitSpecularPeak(specular, 4.0);
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
@@ -3535,6 +3545,18 @@ float3 SampleCosineWorld(float3 N, inout uint rng)
|
||||
N * localDir.z);
|
||||
}
|
||||
|
||||
float3 SampleCosineWorldXi(float3 N, float2 xi)
|
||||
{
|
||||
float3 tangent, bitangent;
|
||||
BuildOrthonormalBasis(N, tangent, bitangent);
|
||||
|
||||
float3 localDir = CosineSampleHemisphere(xi);
|
||||
return normalize(
|
||||
tangent * localDir.x +
|
||||
bitangent * localDir.y +
|
||||
N * localDir.z);
|
||||
}
|
||||
|
||||
float3 SampleConeWorld(float3 centerDir, float coneRadius, inout uint rng)
|
||||
{
|
||||
float3 tangent, bitangent;
|
||||
@@ -4374,7 +4396,21 @@ float3 EstimateReactiveScreenSpaceFinalGather(uint2 pixel, float3 worldPos, floa
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float3 TraceOneIndirectBouncePath(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, inout uint rng)
|
||||
float2 GetStratifiedBounceXi(uint2 pixel, float3 worldPos, float3 pathNormal, uint sampleIndex)
|
||||
{
|
||||
uint spp = max(gSamplesPerPixel, 1u);
|
||||
uint sequenceLength = max(spp * 64u, 64u);
|
||||
uint sequenceIndex = (sampleIndex + (gFrameIndex & 63u) * spp) % sequenceLength;
|
||||
|
||||
float rand = Hash12(
|
||||
(float2)pixel +
|
||||
worldPos.xy * 0.013 +
|
||||
float2(pathNormal.x * 19.19, pathNormal.y * 37.37));
|
||||
|
||||
return Hammersley2D(sequenceIndex, sequenceLength, rand);
|
||||
}
|
||||
|
||||
float3 TraceOneIndirectBouncePath(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, uint sampleIndex, inout uint rng)
|
||||
{
|
||||
const float BOUNCE_TMAX = 1000000.0;
|
||||
|
||||
@@ -4393,7 +4429,10 @@ float3 TraceOneIndirectBouncePath(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
[loop]
|
||||
for (uint depth = 0; depth < maxIndirectDepth; ++depth)
|
||||
{
|
||||
float3 bounceDir = SampleCosineWorld(pathNormal, rng);
|
||||
float2 bounceXi = (depth == 0u)
|
||||
? GetStratifiedBounceXi(pixel, pathPos, pathNormal, sampleIndex)
|
||||
: Rand2(rng);
|
||||
float3 bounceDir = SampleCosineWorldXi(pathNormal, bounceXi);
|
||||
float NoD = saturate(dot(pathNormal, bounceDir));
|
||||
|
||||
float normalBias = lerp(gShadowBias * 3.0, gShadowBias * 0.75, NoD);
|
||||
@@ -4456,6 +4495,7 @@ float3 TraceOneIndirectBouncePath(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
bouncedRadiance += skyTint * 0.045;
|
||||
}
|
||||
|
||||
bouncedRadiance = CompressEmissiveRadiance(bouncedRadiance, depth == 0u ? 8.0 : 5.0);
|
||||
accum += throughput * bouncedRadiance;
|
||||
|
||||
if ((hitGeoFlag & GEOMETRY_FLAG_UNLIT) != 0u)
|
||||
@@ -4487,14 +4527,14 @@ float3 TraceOneIndirectBouncePath(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
return accum;
|
||||
}
|
||||
|
||||
float3 EstimatePathTracedIndirectBounce(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, inout uint rng)
|
||||
float3 EstimatePathTracedIndirectBounce(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, uint sampleIndex, inout uint rng)
|
||||
{
|
||||
if (gMaxBounces <= 1u)
|
||||
return 0.0;
|
||||
|
||||
// One stochastic diffuse path per lighting sample. The path can contain
|
||||
// several diffuse depths, while the temporal pass below handles convergence.
|
||||
float3 accum = TraceOneIndirectBouncePath(pixel, worldPos, N, V, baseAlbedo, rng);
|
||||
float3 accum = TraceOneIndirectBouncePath(pixel, worldPos, N, V, baseAlbedo, sampleIndex, rng);
|
||||
|
||||
const float INDIRECT_STRENGTH = 0.72;
|
||||
return accum * INDIRECT_STRENGTH;
|
||||
@@ -4714,7 +4754,8 @@ float ComputeSpecularReflectionDistanceFade(float hitT, float maxT)
|
||||
|
||||
return fade * fade;
|
||||
}
|
||||
|
||||
)"
|
||||
R"(
|
||||
float3 EstimateRayTracedSpecularReflection(
|
||||
uint2 pixel,
|
||||
float3 worldPos,
|
||||
@@ -4804,6 +4845,7 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
if (hasGBufferMaterial)
|
||||
{
|
||||
float3 hitV = SafeNormalizeOr(-R, V);
|
||||
uint stableHitRng = InitRng(hitPixel, 0u, 0x5EECu);
|
||||
reflectedRadiance = EstimateDirectLightingForBounceHit(
|
||||
hitPixel,
|
||||
hitPos,
|
||||
@@ -4811,7 +4853,7 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
hitV,
|
||||
hitAlbedo,
|
||||
hitGeoFlag,
|
||||
rng);
|
||||
stableHitRng);
|
||||
|
||||
// Reflected glow maps should be visible in the reflection, but still
|
||||
// remain direct radiance; this does not turn emissive into GI.
|
||||
@@ -4827,6 +4869,8 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
}
|
||||
}
|
||||
|
||||
reflectedRadiance = CompressEmissiveRadiance(reflectedRadiance, hasSpecularMap ? 5.0 : 3.5);
|
||||
|
||||
float cavityFade = lerp(0.42, 1.0, saturate(cavity));
|
||||
float reflectionStrength = hasSpecularMap
|
||||
? saturate(specPeak * 1.35)
|
||||
@@ -4968,6 +5012,7 @@ void RayGen()
|
||||
N,
|
||||
V,
|
||||
baseAlbedo,
|
||||
s,
|
||||
rng);
|
||||
}
|
||||
|
||||
@@ -4975,7 +5020,7 @@ void RayGen()
|
||||
lightingAccum += ApplyPrimaryDiffusePost(indirectLighting, ao, microShadow, isSkeletal);
|
||||
}
|
||||
|
||||
uint reflectionRng = InitRng(pixel, gFrameIndex, 0x5EECu);
|
||||
uint reflectionRng = InitRng(pixel, 0u, 0x5EECu);
|
||||
float3 reflectedSpecular = EstimateRayTracedSpecularReflection(
|
||||
pixel,
|
||||
worldPos,
|
||||
@@ -5334,9 +5379,9 @@ float3 SafeNormalTemporal(float3 n)
|
||||
|
||||
float3 ClampHistoryToCurrent(float3 history, float3 current)
|
||||
{
|
||||
// Loose temporal clamp: it removes GI fireflies and old lighting while still
|
||||
// allowing bright muzzle-flash/door-light changes to appear in a few frames.
|
||||
float3 radius = 0.20 + abs(current) * 0.55;
|
||||
// Clamp enough to kill rare GI/volume fireflies before they enter history,
|
||||
// while still allowing real dynamic light changes to pull the accumulator.
|
||||
float3 radius = 0.12 + abs(current) * 0.42;
|
||||
return clamp(history, current - radius, current + radius);
|
||||
}
|
||||
|
||||
@@ -5359,7 +5404,7 @@ void TemporalAccumCS(uint3 dispatchThreadId : SV_DispatchThreadID)
|
||||
}
|
||||
|
||||
float4 history = gHistoryTex.Load(int3(pixel, 0));
|
||||
float historyCount = (gFrameIndex == 0u) ? 0.0 : clamp(history.a, 0.0, 31.0);
|
||||
float historyCount = (gFrameIndex == 0u) ? 0.0 : clamp(history.a, 0.0, 63.0);
|
||||
|
||||
if (historyCount <= 0.0)
|
||||
{
|
||||
@@ -5374,14 +5419,14 @@ void TemporalAccumCS(uint3 dispatchThreadId : SV_DispatchThreadID)
|
||||
float histLum = LuminanceTemporal(historyColor);
|
||||
float relChange = abs(rawLum - histLum) / max(max(rawLum, histLum), 0.08);
|
||||
|
||||
// Base accumulation approaches 32 frames, but large lighting changes raise
|
||||
// Base accumulation approaches 64 frames, but large lighting changes raise
|
||||
// current-frame weight so the accumulator does not leave obvious trails.
|
||||
float currentWeight = max(1.0 / (historyCount + 1.0), 0.055);
|
||||
currentWeight = max(currentWeight, saturate(relChange * 0.28));
|
||||
float currentWeight = max(1.0 / (historyCount + 1.0), 0.035);
|
||||
currentWeight = max(currentWeight, saturate(relChange * 0.24));
|
||||
currentWeight = saturate(currentWeight);
|
||||
|
||||
float3 resolved = lerp(historyColor, max(raw.rgb, 0.0), currentWeight);
|
||||
float nextCount = min(historyCount + 1.0, 31.0);
|
||||
float nextCount = min(historyCount + 1.0, 63.0);
|
||||
|
||||
gTemporalOutTex[pixel] = float4(resolved, raw.a);
|
||||
gHistoryOutTex[pixel] = float4(resolved, nextCount);
|
||||
@@ -7323,4 +7368,4 @@ void glRaytracingShowAllInstances(void)
|
||||
|
||||
for (int i = 0; i < GL_RAYTRACING_MAX_RENDER_WORLDS; ++i)
|
||||
glRaytracingSetAllInstancesVisibleUnlocked(&g_glRaytracingScene.worlds[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user