TAA / FSR: shadow edges move / settle when an animated avatar part (e.g. a wing) passes in front of them #608

Closed
opened 2026-10-09 23:19:24 +00:00 by sky_line · 1 comment
Owner

When part of an avatar moves quickly in front of a static shadow edge (a flapping wing, a waving arm, a tail), the shadow edge behind it visibly moves or "settles" for a moment after the moving part passes. It looks like the shadow edge crawls back into place over several frames.

Likely cause

The pixels the moving part uncovers, and the ones it covers, lose their temporal history in TAA / FSR. That happens through the disocclusion and reactive handling triggered by the avatar's motion vectors and the reactive / avatar mask. Without history, those pixels show the current frame's raw, undersampled shadow edge (jittered, and for ray-traced shadows 1 sample per pixel). They then re-converge over the history window, and that re-convergence is the visible settling.

Investigate

  • Which signal throws the history away on those pixels: depth-based disocclusion, the motion-vector difference, the reactive mask written for avatar / alpha pixels, or the dilation of any of these. The rejected region may be wider than the pixels that actually changed (e.g. a dilated reactive mask, or motion dilation taking the wing's velocity onto the static background behind it).
  • Whether it happens with shadow maps as well as ray-traced shadows (RenderVKSunShadows, RenderVKProjectorShadows), with TAA only, with FSR only, and with RenderVKReactiveMask off. Also with motion blur off (it runs before the resolve now).
  • RenderVKTAADebug 1 (history weight) while a wing flaps over a shadow edge: how big the rejected area is, and how long it takes to recover.

Possible fixes

  • Tighten the rejection to the pixels that really changed. Static background behind a moving foreground keeps its own (zero) motion, with no dilated foreground velocity on it, and only real disocclusions reset.
  • Give the shadow term its own temporal stability independent of the final TAA / FSR history: temporal accumulation of the RT shadow mask (#85 child 1, with its own reprojection and disocclusion test), so a resolve-history reset does not reveal a raw shadow edge.
  • Faster, cleaner re-convergence after a reset, e.g. variance-clipped neighbourhood clamping rather than a long blend.

Related: #85 (RT denoiser), #605 (per-pixel no-history mask; the same mask plumbing), #118 (motion blur before the resolve).

When part of an avatar moves quickly in front of a static shadow edge (a flapping wing, a waving arm, a tail), the shadow edge behind it visibly moves or "settles" for a moment after the moving part passes. It looks like the shadow edge crawls back into place over several frames. ## Likely cause The pixels the moving part uncovers, and the ones it covers, lose their temporal history in TAA / FSR. That happens through the disocclusion and reactive handling triggered by the avatar's motion vectors and the reactive / avatar mask. Without history, those pixels show the current frame's raw, undersampled shadow edge (jittered, and for ray-traced shadows 1 sample per pixel). They then re-converge over the history window, and that re-convergence is the visible settling. ## Investigate - Which signal throws the history away on those pixels: depth-based disocclusion, the motion-vector difference, the reactive mask written for avatar / alpha pixels, or the dilation of any of these. The rejected region may be wider than the pixels that actually changed (e.g. a dilated reactive mask, or motion dilation taking the wing's velocity onto the static background behind it). - Whether it happens with shadow maps as well as ray-traced shadows (RenderVKSunShadows, RenderVKProjectorShadows), with TAA only, with FSR only, and with RenderVKReactiveMask off. Also with motion blur off (it runs before the resolve now). - RenderVKTAADebug 1 (history weight) while a wing flaps over a shadow edge: how big the rejected area is, and how long it takes to recover. ## Possible fixes - Tighten the rejection to the pixels that really changed. Static background behind a moving foreground keeps its own (zero) motion, with no dilated foreground velocity on it, and only real disocclusions reset. - Give the shadow term its own temporal stability independent of the final TAA / FSR history: temporal accumulation of the RT shadow mask (#85 child 1, with its own reprojection and disocclusion test), so a resolve-history reset does not reveal a raw shadow edge. - Faster, cleaner re-convergence after a reset, e.g. variance-clipped neighbourhood clamping rather than a long blend. Related: #85 (RT denoiser), #605 (per-pixel no-history mask; the same mask plumbing), #118 (motion blur before the resolve).
sky_line added this to the Slipstream project 2026-10-09 23:19:24 +00:00
Author
Owner

Shipped in 1.2.0 Beta 8 (and in 1.2.0): the RT shadow history is now SVGF-style, which fixed the shadow edges settling when an animated avatar part moves. Verified by the owner.

Shipped in 1.2.0 Beta 8 (and in 1.2.0): the RT shadow history is now SVGF-style, which fixed the shadow edges settling when an animated avatar part moves. Verified by the owner.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#608
No description provided.