From 4aae6af65f547060e047cbcf5a38af228e6f1f68 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:18:02 -0500 Subject: [PATCH 1/3] Fix solari GI shadow regression --- crates/bevy_solari/src/realtime/restir_gi.wgsl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 7d3a60ac9e6d3..d41b3b70b76a3 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -67,9 +67,7 @@ fn spatial_and_shade(@builtin(global_invocation_id) global_id: vec3) { let spatial = load_spatial_reservoir(global_id.xy, depth, surface.world_position, surface.world_normal, &rng); let merge_result = merge_reservoirs(input_reservoir, surface.world_position, surface.world_normal, surface.material.base_color / PI, spatial.reservoir, spatial.world_position, spatial.world_normal, spatial.diffuse_brdf, &rng); - var combined_reservoir = merge_result.merged_reservoir; - - combined_reservoir.radiance *= trace_point_visibility(surface.world_position, combined_reservoir.sample_point_world_position); + let combined_reservoir = merge_result.merged_reservoir; gi_reservoirs_a[pixel_index] = combined_reservoir; @@ -164,7 +162,9 @@ fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3< } let spatial_pixel_index = spatial_pixel_id.x + spatial_pixel_id.y * u32(view.main_pass_viewport.z); - let spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; + var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; + + spatial_reservoir.radiance *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); return NeighborInfo(spatial_reservoir, spatial_surface.world_position, spatial_surface.world_normal, spatial_diffuse_brdf); } From 7e165b550831afbaa4b49ea77dc968144878f6f8 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:45:49 -0500 Subject: [PATCH 2/3] Solari: Misc improvements --- .../bevy_solari/src/realtime/restir_di.wgsl | 16 +++++++----- .../bevy_solari/src/realtime/restir_gi.wgsl | 26 +++++++++++-------- .../src/realtime/world_cache_query.wgsl | 3 ++- .../src/scene/raytracing_scene_bindings.wgsl | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_di.wgsl b/crates/bevy_solari/src/realtime/restir_di.wgsl index b31f70f49963e..e7492f3c47ff3 100644 --- a/crates/bevy_solari/src/realtime/restir_di.wgsl +++ b/crates/bevy_solari/src/realtime/restir_di.wgsl @@ -179,15 +179,19 @@ fn load_temporal_reservoir_inner(temporal_pixel_id: vec2, depth: f32, world } fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3, world_normal: vec3, rng: ptr) -> Reservoir { - let spatial_pixel_id = get_neighbor_pixel_id(pixel_id, rng); + for (var i = 0u; i < 5u; i++) { + let spatial_pixel_id = get_neighbor_pixel_id(pixel_id, rng); - let spatial_depth = textureLoad(depth_buffer, spatial_pixel_id, 0); - let spatial_surface = gpixel_resolve(textureLoad(gbuffer, spatial_pixel_id, 0), spatial_depth, spatial_pixel_id, view.main_pass_viewport.zw, view.world_from_clip); - if pixel_dissimilar(depth, world_position, spatial_surface.world_position, world_normal, spatial_surface.world_normal, view) { - return empty_reservoir(); + let spatial_depth = textureLoad(depth_buffer, spatial_pixel_id, 0); + let spatial_surface = gpixel_resolve(textureLoad(gbuffer, spatial_pixel_id, 0), spatial_depth, spatial_pixel_id, view.main_pass_viewport.zw, view.world_from_clip); + if pixel_dissimilar(depth, world_position, spatial_surface.world_position, world_normal, spatial_surface.world_normal, view) { + continue; + } + + return load_reservoir_b(spatial_pixel_id); } - return load_reservoir_b(spatial_pixel_id); + return empty_reservoir(); } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index b0bbfa90ba421..a6355517af5c2 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -152,21 +152,25 @@ fn load_temporal_reservoir_inner(temporal_pixel_id: vec2, depth: f32, world } fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3, world_normal: vec3, rng: ptr) -> NeighborInfo { - let spatial_pixel_id = get_neighbor_pixel_id(pixel_id, rng); + for (var i = 0u; i < 5u; i++) { + let spatial_pixel_id = get_neighbor_pixel_id(pixel_id, rng); - let spatial_depth = textureLoad(depth_buffer, spatial_pixel_id, 0); - let spatial_surface = gpixel_resolve(textureLoad(gbuffer, spatial_pixel_id, 0), spatial_depth, spatial_pixel_id, view.main_pass_viewport.zw, view.world_from_clip); - let spatial_diffuse_brdf = spatial_surface.material.base_color / PI; - if pixel_dissimilar(depth, world_position, spatial_surface.world_position, world_normal, spatial_surface.world_normal, view) { - return NeighborInfo(empty_reservoir(), spatial_surface.world_position, spatial_surface.world_normal, spatial_diffuse_brdf); - } + let spatial_depth = textureLoad(depth_buffer, spatial_pixel_id, 0); + let spatial_surface = gpixel_resolve(textureLoad(gbuffer, spatial_pixel_id, 0), spatial_depth, spatial_pixel_id, view.main_pass_viewport.zw, view.world_from_clip); + let spatial_diffuse_brdf = spatial_surface.material.base_color / PI; + if pixel_dissimilar(depth, world_position, spatial_surface.world_position, world_normal, spatial_surface.world_normal, view) { + continue; + } + + let spatial_pixel_index = spatial_pixel_id.x + spatial_pixel_id.y * u32(view.main_pass_viewport.z); + var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; - let spatial_pixel_index = spatial_pixel_id.x + spatial_pixel_id.y * u32(view.main_pass_viewport.z); - var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; + spatial_reservoir.radiance *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); - spatial_reservoir.radiance *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); + return NeighborInfo(spatial_reservoir, spatial_surface.world_position, spatial_surface.world_normal, spatial_diffuse_brdf); + } - return NeighborInfo(spatial_reservoir, spatial_surface.world_position, spatial_surface.world_normal, spatial_diffuse_brdf); + return NeighborInfo(empty_reservoir(), world_position, world_normal, vec3(0.0)); } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { diff --git a/crates/bevy_solari/src/realtime/world_cache_query.wgsl b/crates/bevy_solari/src/realtime/world_cache_query.wgsl index 64a7d67fdd4ee..d6644919b255e 100644 --- a/crates/bevy_solari/src/realtime/world_cache_query.wgsl +++ b/crates/bevy_solari/src/realtime/world_cache_query.wgsl @@ -47,12 +47,13 @@ struct WorldCacheGeometryData { #ifndef WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER fn query_world_cache(world_position: vec3, world_normal: vec3, view_position: vec3, cell_lifetime: u32, rng: ptr) -> vec3 { - let cell_size = get_cell_size(world_position, view_position); + var cell_size = get_cell_size(world_position, view_position); // https://tomclabault.github.io/blog/2025/regir, jitter_world_position_tangent_plane let TBN = orthonormalize(world_normal); let offset = (rand_vec2f(rng) * 2.0 - 1.0) * cell_size * 0.5; let jittered_position = world_position + offset.x * TBN[0] + offset.y * TBN[1]; + cell_size = get_cell_size(jittered_position, view_position); let world_position_quantized = bitcast>(quantize_position(jittered_position, cell_size)); let world_normal_quantized = bitcast>(quantize_normal(world_normal)); diff --git a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl index 8b1e875fc5423..4d5ec4584db33 100644 --- a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl +++ b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl @@ -83,7 +83,7 @@ const LIGHT_NOT_PRESENT_THIS_FRAME = 0xFFFFFFFFu; @group(0) @binding(10) var directional_lights: array; @group(0) @binding(11) var previous_frame_light_id_translations: array; -const RAY_T_MIN = 0.01f; +const RAY_T_MIN = 0.001f; const RAY_T_MAX = 100000.0f; const RAY_NO_CULL = 0xFFu; From b2a892b072b0fe7c9b68ea3acb2edb0441c39329 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Thu, 27 Nov 2025 00:11:47 -0500 Subject: [PATCH 3/3] Checksum check --- crates/bevy_solari/src/realtime/world_cache_query.wgsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_solari/src/realtime/world_cache_query.wgsl b/crates/bevy_solari/src/realtime/world_cache_query.wgsl index d6644919b255e..cafefffac58a8 100644 --- a/crates/bevy_solari/src/realtime/world_cache_query.wgsl +++ b/crates/bevy_solari/src/realtime/world_cache_query.wgsl @@ -122,7 +122,7 @@ fn compute_checksum(world_position: vec3, world_normal: vec3) -> u32 { key = iqint_hash(key + world_normal.x); key = iqint_hash(key + world_normal.y); key = iqint_hash(key + world_normal.z); - return key; + return max(key, 1u); // 0u is reserved for WORLD_CACHE_EMPTY_CELL } fn pcg_hash(input: u32) -> u32 {