Skip to content

Conversation

@JMS55
Copy link
Contributor

@JMS55 JMS55 commented Jan 2, 2026

Objective

  • Greatly reduce light leaks near corners of objects (but doesn't fix general light leaks from tiny geometry)

Solution

To prevent light leaks:

  • When ray_t is smaller than the cache cell size, force the finest LOD cache access.
  • Make LOD much less aggressive
  • Make the finest LOD smaller

Since this then greatly increases the number of cache cells in the scene, I changed the following to prevent too much of a decrease in performance (this PR is still a hit to performance though):

  • Randomly skip updating some cells once we have more than 40,000 cells active
  • Aggressively prune older cache cells

Also some misc changes:

Ideally the skipped cells wouldn't be totally random, and we'd have coarser-LOD cells update less frequently, but that would get very complicated as we'd have to track the total amount of cells per LOD in order to average out to WORLD_CACHE_TARGET_CELL_UPDATES.

@JMS55 JMS55 marked this pull request as draft January 2, 2026 04:05
@JMS55 JMS55 requested a review from SparkyPotato January 2, 2026 04:05
@JMS55 JMS55 added A-Rendering Drawing game state to the screen C-Refinement Improves output quality, without fixing a clear bug or adding new functionality. labels Jan 2, 2026
// Path spread is wide enough, terminate path in the world cache
let diffuse_brdf = ray_hit.material.base_color / PI;
radiance += throughput * diffuse_brdf * query_world_cache(ray_hit.world_position, ray_hit.geometric_world_normal, view.world_position, WORLD_CACHE_CELL_LIFETIME, rng);
radiance += throughput * diffuse_brdf * query_world_cache(ray_hit.world_position, ray_hit.geometric_world_normal, view.world_position, ray.t, WORLD_CACHE_CELL_LIFETIME, rng);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be ok if it were only done for the first trace? Or do all the bounces need to care about light leaks?


if rand_f(&rng) >= f32(WORLD_CACHE_TARGET_CELL_UPDATES) / f32(world_cache_active_cells_count) { return; }

let ray_direction = sample_cosine_hemisphere(geometry_data.world_normal, &rng);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the #ifndef NO_MULTIBOUNCE

new_radiance += ray_hit.material.base_color * query_world_cache(ray_hit.world_position, ray_hit.geometric_world_normal, view.world_position, ray.t, cell_life, &rng);
}

world_cache_active_cells_new_radiance[active_cell_id.x] = new_radiance;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably just be a += here instead of having to load early and then store (might improve register pressure?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Refinement Improves output quality, without fixing a clear bug or adding new functionality.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants