AO: faint diagonal banding on smooth surfaces that scrolls with the camera (worse with FSR) #843

Closed
opened 2026-10-18 06:17:03 +00:00 by sky_line · 2 comments
Owner

Ambient occlusion produces faint diagonal banding streaks on smooth surfaces (an avatar's body in the screenshot). The pattern scrolls with the camera, and FSR (native AA) makes the scrolling more noticeable. The owner attributes it to AO (it goes away with AO off).

Suspects

  • #828 (beta 13): replaced the per-tap textureSize(uViewZ, lv) in clean_ao.comp tapPos with max(screen >> lv, 1), on the assumption that the chain is always built at the screen's size. If the depth pyramid's level sizes round up (ceil) at odd intermediate sizes while the shader rounds down (>>), the tap UVs are mis-scaled on those levels. That gives structured, position-dependent banding. E.g. at 3840x2088, level 4 is 130 vs 131 texels tall. The new SPD pyramid (RenderVKAODepthSPD) may also size levels differently from the old #648 build.
  • AO noise not integrating: the per-frame GTAO noise (interleaved-gradient style) rotating with the camera / TAA jitter, producing scrolling diagonal stripes if the temporal resolve or AO blur doesn't integrate it. FSR's reactivity / history can make it more visible.
  • The #648 depth-MIP normal reconstruction (facet lines / bands, partly addressed in AO round 2).

Expected

Smooth AO on smooth surfaces with no banding or crawling pattern, with FSR / TAA on and off.

AO banding

Ambient occlusion produces faint **diagonal banding streaks** on smooth surfaces (an avatar's body in the screenshot). The pattern **scrolls** with the camera, and FSR (native AA) makes the scrolling more noticeable. The owner attributes it to AO (it goes away with AO off). ### Suspects - **#828 (beta 13):** replaced the per-tap `textureSize(uViewZ, lv)` in `clean_ao.comp` `tapPos` with `max(screen >> lv, 1)`, on the assumption that the chain is always built at the screen's size. If the depth pyramid's level sizes round **up** (ceil) at odd intermediate sizes while the shader rounds **down** (`>>`), the tap UVs are mis-scaled on those levels. That gives structured, position-dependent banding. E.g. at 3840x2088, level 4 is 130 vs 131 texels tall. The new SPD pyramid (`RenderVKAODepthSPD`) may also size levels differently from the old #648 build. - **AO noise not integrating:** the per-frame GTAO noise (interleaved-gradient style) rotating with the camera / TAA jitter, producing scrolling diagonal stripes if the temporal resolve or AO blur doesn't integrate it. FSR's reactivity / history can make it more visible. - The #648 depth-MIP normal reconstruction (facet lines / bands, partly addressed in AO round 2). ### Expected Smooth AO on smooth surfaces with no banding or crawling pattern, with FSR / TAA on and off. ![AO banding](https://git.slipstreamviewer.org/attachments/5bdb862d-6c8b-49bd-9499-fc961711e10e)
sky_line added this to the Slipstream project 2026-10-18 06:17:03 +00:00
Author
Owner

Root cause, from the reporter's A/B test: raising RenderVKGTAOSlices from 2 to 8 removes the banding completely. Raising RenderVKGTAOSteps to 16 only masks it.

So the bands come from too few slice directions per pixel. Each pixel integrates 2 slice directions, offset by interleaved-gradient noise (IGN). On a curved surface the occlusion varies smoothly with slice angle, so the result picks up IGN's diagonal lattice pattern. The small blur can't remove it, and half resolution doubles its size.

The noise only changes per frame under TAA/FSR, through the TAA frame counter. That means it never converges without TAA, and the leftover pattern shifts frame to frame with FSR (the scroll).

Fix in progress:
(A) Hilbert-curve plus R2 noise driven by the AO's own frame counter. This is the hotfix candidate.
(B) An AO temporal accumulator that does not depend on TAA/FSR.

Root cause, from the reporter's A/B test: raising RenderVKGTAOSlices from 2 to 8 removes the banding completely. Raising RenderVKGTAOSteps to 16 only masks it. So the bands come from too few slice directions per pixel. Each pixel integrates 2 slice directions, offset by interleaved-gradient noise (IGN). On a curved surface the occlusion varies smoothly with slice angle, so the result picks up IGN's diagonal lattice pattern. The small blur can't remove it, and half resolution doubles its size. The noise only changes per frame under TAA/FSR, through the TAA frame counter. That means it never converges without TAA, and the leftover pattern shifts frame to frame with FSR (the scroll). Fix in progress: (A) Hilbert-curve plus R2 noise driven by the AO's own frame counter. This is the hotfix candidate. (B) An AO temporal accumulator that does not depend on TAA/FSR.
Author
Owner

Fixed in Slipstream 1.3.0 (stable): https://git.slipstreamviewer.org/sky_line/Slipstream/releases/tag/v1.3.0

If you still see this on 1.3.0, reply here and we'll reopen it.

Fixed in **Slipstream 1.3.0** (stable): https://git.slipstreamviewer.org/sky_line/Slipstream/releases/tag/v1.3.0 If you still see this on 1.3.0, reply here and we'll reopen it.
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#843
No description provided.