Reflection probes: rectangular boxes of unprobed lighting at some zoom levels #249

Closed
opened 2026-10-02 12:40:33 +00:00 by sky_line · 2 comments
Owner

Report

Zooming out from a house covered by several manual reflection probes, some zoom levels show screen-aligned rectangular "boxes" where probe lighting drops out. Those regions look like non-probed / default lighting, brighter than the surrounding probe-lit area. The boxes change with zoom level.

This is not new; it predates the deferred-lighting work.

Separately (to be tracked in its own issue), the probes make the house look darker than it should.

Suspects

The rectangles are screen-aligned and change with distance, which points at per-cluster probe selection in the VK clustered probe path (P2 clustered selection, probe cluster buffers):

  • a cluster's probe list hits its cap when zoomed out, so probes are dropped and the cluster falls back to the default probe;
  • the probe-volume vs cluster-AABB test is wrong at some depth slices (reversed-Z, slice distribution, far clusters);
  • probe cull (probe cull: log line) rejects probes per view, by distance or the screen-size cutoff, at certain zooms, and the rejection isn't applied uniformly across clusters.

The deferred lighting compute's per-tile lists and the probe top-N (RenderVKProbeTopN) could make this worse, but don't cause it.

Repro

A house with several manual probes, zooming out slowly. A screenshot is saved in research/screens/probe_boxes.png in the local tree.

## Report Zooming out from a house covered by several manual reflection probes, some zoom levels show screen-aligned rectangular **"boxes" where probe lighting drops out**. Those regions look like non-probed / default lighting, brighter than the surrounding probe-lit area. The boxes change with zoom level. This is not new; it predates the deferred-lighting work. Separately (to be tracked in its own issue), the probes make the house look darker than it should. ## Suspects The rectangles are screen-aligned and change with distance, which points at **per-cluster probe selection** in the VK clustered probe path (P2 clustered selection, probe cluster buffers): - a cluster's probe list hits its cap when zoomed out, so probes are dropped and the cluster falls back to the default probe; - the probe-volume vs cluster-AABB test is wrong at some depth slices (reversed-Z, slice distribution, far clusters); - probe cull (`probe cull:` log line) rejects probes per view, by distance or the screen-size cutoff, at certain zooms, and the rejection isn't applied uniformly across clusters. The deferred lighting compute's per-tile lists and the probe top-N (`RenderVKProbeTopN`) could make this worse, but don't cause it. ## Repro A house with several manual probes, zooming out slowly. A screenshot is saved in `research/screens/probe_boxes.png` in the local tree.
Author
Owner

Findings (branch probebox, commits ba753650f0 + 16eedb6662; not yet built or tested in the viewer)

Root cause: the per-cluster probe cap overflowed, and the probes it kept were the wrong ones. clean_probe_cluster.comp listed the first 16 probes that touched a cluster, in upload order. Upload order is nearest-first by |centre - camera| - radius (llappviewer.cpp p.dist). At default level 3, terrain-grid probes (r ≈ 27.7 m, 32 m spacing) and octree automatic probes (r = 8–30 m) therefore sort 10–20 m "nearer" than the house's small manual boxes (r ≈ 5–10 m) at the same place. In an overflowing cluster the manual probes were the ones dropped. That cluster (one screen tile × one depth slice) then got automatic-only lighting, while the neighbouring clusters had the manual probes (which override the automatic class where they cover a pixel). The result is screen-aligned, lighter rectangles.

Numbers (zn 0.1, draw distance 256 m, 60° fov, 16:9; grid 16×9×24):

  • The slice factor is 1.387. At 40 m the slice spans about 36–50 m, and a tile is about 6.4 m wide at 50 m. Zoomed in to 10 m, a tile is about 1.3 m.
  • Candidates for a 40 m cluster near the house: about 4 grid + 8–16 octree + 5–15 manual, which is well over 16. The cluster size grows with distance, so the boxes appear and change with zoom.

Checked and not at fault:

  • tile/NDC y-convention (P carries the Vulkan y-flip);
  • the slice formula and zinfo.z agree between the build and the lookup;
  • deferred g_frag_xy and grid.xy are both in render pixels;
  • the sphere-vs-AABB test, and the circumscribed radius used for box probes;
  • the active set vs. the indices: cluster indices point into the compacted upload, which is rebuilt in the same frame before the dispatch, behind a barrier.

Fix

  • Prioritised selection when over the cap. The shader counts candidates per class. Within the cap it keeps all of them. Over the cap it keeps the manual class first but always reserves 6 slots for automatic probes. Within each class it keeps the probes with the most influence over the cluster: manual ranked by distance / radius, automatic by distance in metres (matching their 1/d weight).
  • PROBE_CLUSTER_CAP raised from 16 to 24, in both the shader and LLCleanRendererVK.
  • probe_count = kept | candidates << 16; the sampler masks the low half.
  • The last depth slice now reaches the projection far, not just the draw distance. Pixels beyond the draw distance used to be clamped into a slice whose box ended at the draw distance. That slice is still ranked on its own depth range.
  • The CPU slot fill takes non-resident manual probes first. This only matters when RenderReflectionProbeCount is below the number of candidates (the default is 256).

Debug aid: RenderVKDebugView 17

Shows each pixel's cluster probe list. Fullbright faces aren't painted. The deferred path falls back to forward while it is on.

  • Green: number of listed probes / cap.
  • Blue: a manual probe is listed.
  • Red: the cluster overflowed; brighter means further over the cap.
  • Dark grey: default probe only.

Before the fix, the boxes would have shown as red tiles with no blue over the house. After it, the house should be blue wherever manual probes cover it; red can remain, but the lighting should be continuous.

Test

  1. Zoom out slowly from the house with view 0 and look for boxes.
  2. Repeat with view 17 to see the overflow.
  3. Also check at the draw-distance edge.

Darkness (separate issue)

Not the same root cause. Under a manual box at depth ≥ 0.25, m = min(dwsum[manual], 1) is 1, which fully replaces automatic/sky irradiance. A low-ambiance or dark interior capture therefore darkens the house; that is the lead to follow.

## Findings (branch `probebox`, commits ba753650f0 + 16eedb6662; not yet built or tested in the viewer) **Root cause: the per-cluster probe cap overflowed, and the probes it kept were the wrong ones.** `clean_probe_cluster.comp` listed the **first** 16 probes that touched a cluster, in upload order. Upload order is nearest-first by `|centre - camera| - radius` (`llappviewer.cpp` `p.dist`). At default level 3, terrain-grid probes (r ≈ 27.7 m, 32 m spacing) and octree automatic probes (r = 8–30 m) therefore sort 10–20 m "nearer" than the house's small manual boxes (r ≈ 5–10 m) at the same place. In an overflowing cluster the manual probes were the ones dropped. That cluster (one screen tile × one depth slice) then got automatic-only lighting, while the neighbouring clusters had the manual probes (which override the automatic class where they cover a pixel). The result is screen-aligned, lighter rectangles. Numbers (zn 0.1, draw distance 256 m, 60° fov, 16:9; grid 16×9×24): - The slice factor is 1.387. At 40 m the slice spans about 36–50 m, and a tile is about 6.4 m wide at 50 m. Zoomed in to 10 m, a tile is about 1.3 m. - Candidates for a 40 m cluster near the house: about 4 grid + 8–16 octree + 5–15 manual, which is well over 16. The cluster size grows with distance, so the boxes appear and change with zoom. Checked and **not** at fault: - tile/NDC y-convention (P carries the Vulkan y-flip); - the slice formula and `zinfo.z` agree between the build and the lookup; - deferred `g_frag_xy` and `grid.xy` are both in render pixels; - the sphere-vs-AABB test, and the circumscribed radius used for box probes; - the active set vs. the indices: cluster indices point into the compacted upload, which is rebuilt in the same frame before the dispatch, behind a barrier. ## Fix - **Prioritised selection when over the cap.** The shader counts candidates per class. Within the cap it keeps all of them. Over the cap it keeps the manual class first but always reserves 6 slots for automatic probes. Within each class it keeps the probes with the most influence over the cluster: manual ranked by distance / radius, automatic by distance in metres (matching their `1/d` weight). - `PROBE_CLUSTER_CAP` raised from 16 to 24, in both the shader and `LLCleanRendererVK`. - `probe_count = kept | candidates << 16`; the sampler masks the low half. - The last depth slice now reaches the projection far, not just the draw distance. Pixels beyond the draw distance used to be clamped into a slice whose box ended at the draw distance. That slice is still ranked on its own depth range. - The CPU slot fill takes non-resident manual probes first. This only matters when `RenderReflectionProbeCount` is below the number of candidates (the default is 256). ## Debug aid: `RenderVKDebugView 17` Shows each pixel's cluster probe list. Fullbright faces aren't painted. The deferred path falls back to forward while it is on. - **Green**: number of listed probes / cap. - **Blue**: a manual probe is listed. - **Red**: the cluster overflowed; brighter means further over the cap. - **Dark grey**: default probe only. Before the fix, the boxes would have shown as red tiles with no blue over the house. After it, the house should be blue wherever manual probes cover it; red can remain, but the lighting should be continuous. ## Test 1. Zoom out slowly from the house with view 0 and look for boxes. 2. Repeat with view 17 to see the overflow. 3. Also check at the draw-distance edge. ## Darkness (separate issue) Not the same root cause. Under a manual box at depth ≥ 0.25, `m = min(dwsum[manual], 1)` is 1, which fully replaces automatic/sky irradiance. A low-ambiance or dark interior capture therefore darkens the house; that is the lead to follow.
sky_line added this to the Slipstream project 2026-10-06 15:04:15 +00:00
Author
Owner

Ticket audit 2026-10-07: done and shipped in 1.0.0 Beta 1. Ranked per-cluster probe selection keeps manual probes, cap raised 16 -> 24, debug view 17 (ba753650f0, 16eedb6662). Probe darkness is tracked in #250. If you still see the problem on the current beta, please reopen or file a new report.

Ticket audit 2026-10-07: done and shipped in **1.0.0 Beta 1**. Ranked per-cluster probe selection keeps manual probes, cap raised 16 -> 24, debug view 17 (ba753650f0, 16eedb6662). Probe darkness is tracked in #250. If you still see the problem on the current beta, please reopen or file a new report.
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#249
No description provided.