Skeletal pixels now bypass the internal temporal accumulato

This commit is contained in:
Justin Marshall
2026-05-24 15:52:51 -07:00
parent 4ccdb56258
commit 26dd7e649e
2 changed files with 21 additions and 3 deletions
+16 -2
View File
@@ -5399,6 +5399,10 @@ float3 EstimateRayTracedSpecularReflection(
R"(
float3 ApplyRealisticOutputCurve(float3 color)
{
color.r = ((color.r == color.r) && abs(color.r) < 65504.0) ? color.r : 0.0;
color.g = ((color.g == color.g) && abs(color.g) < 65504.0) ? color.g : 0.0;
color.b = ((color.b == color.b) && abs(color.b) < 65504.0) ? color.b : 0.0;
// Final photographic shoulder only: it does not change light radius or
// attenuation, but it prevents intense local lights/specular/bloom from
// clipping into a flat white patch. Values below 1.0 are left untouched.
@@ -5935,6 +5939,18 @@ void TemporalAccumCS(uint3 dispatchThreadId : SV_DispatchThreadID)
float4 history = gHistoryTex.Load(int3(pixel, 0));
float historyCount = (gFrameIndex == 0u) ? 0.0 : clamp(history.a, 0.0, 63.0);
// This temporal accumulator has no reprojection/object history validation.
// Animated characters can inherit the previous frame's wall/background color
// at the same screen pixel, which shows up as grey path-trace-only dirt even
// though the current G-buffer is clean. Keep skeletal pixels current-frame
// and let the following geometry-aware spatial pass do the filtering.
if (isSkeletal)
{
gTemporalOutTex[pixel] = raw;
gHistoryOutTex[pixel] = float4(raw.rgb, 0.0);
return;
}
if (historyCount <= 0.0)
{
gTemporalOutTex[pixel] = raw;
@@ -5952,8 +5968,6 @@ void TemporalAccumCS(uint3 dispatchThreadId : SV_DispatchThreadID)
// current-frame weight so the accumulator does not leave obvious trails.
float currentWeight = max(1.0 / (historyCount + 1.0), 0.035);
currentWeight = max(currentWeight, saturate(relChange * 0.24));
if (isSkeletal)
currentWeight = max(currentWeight, 0.25);
currentWeight = saturate(currentWeight);
float3 resolved = lerp(historyColor, max(raw.rgb, 0.0), currentWeight);
+5 -1
View File
@@ -4122,6 +4122,7 @@ VSOut VSMain(VSIn i)
float3 worldBinormal = mul((float3x3)gModelMatrix, i.binormal);
currClip.z = 0.5 * (currClip.z + currClip.w);
prevClip.z = 0.5 * (prevClip.z + prevClip.w);
o.pos = currClip;
o.currClip = currClip;
@@ -4366,6 +4367,7 @@ VSOut DSMain(HSConstOut tessFactors, float3 bary : SV_DomainLocation, const Outp
float3 worldNormal = mul((float3x3)gModelMatrix, objNormal);
currClip.z = 0.5 * (currClip.z + currClip.w);
prevClip.z = 0.5 * (prevClip.z + prevClip.w);
o.pos = currClip;
o.currClip = currClip;
@@ -7571,7 +7573,9 @@ static sl::Result QD3D12_SetStreamlineCommonConstants(sl::FrameToken& frameToken
memcpy(&consts.clipToPrevClip, g_gl.cameraState.clipToPrevClip.m, sizeof(float) * 16);
memcpy(&consts.prevClipToClip, g_gl.cameraState.prevClipToClip.m, sizeof(float) * 16);
consts.jitterOffset = { g_gl.jitterX, g_gl.jitterY };
consts.mvecScale = { 1.0f, 1.0f }; // motion vectors are written in PreviousUV - CurrentUV
const float motionScaleX = g_currentWindow ? (float)g_currentWindow->renderWidth : 1.0f;
const float motionScaleY = g_currentWindow ? (float)g_currentWindow->renderHeight : 1.0f;
consts.mvecScale = { motionScaleX, motionScaleY }; // motion vectors are written in PreviousUV - CurrentUV
consts.cameraPinholeOffset = { 0.0f, 0.0f };
memcpy(&consts.cameraPos, g_gl.cameraState.cameraPos, sizeof(float) * 3);
memcpy(&consts.cameraRight, g_gl.cameraState.cameraRight, sizeof(float) * 3);