From 18816cf0b2fe03ca188c83f958bcc16f04704d0b Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Tue, 22 Jul 2025 23:28:16 -0400 Subject: [PATCH 1/7] Clamp jacobian to reduce bright spots --- crates/bevy_solari/src/realtime/restir_gi.wgsl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 2be5e8554dba9..607040567502f 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -155,16 +155,12 @@ 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.viewport.z); var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; - var jacobian = jacobian( + spatial_reservoir.unbiased_contribution_weight *= jacobian( world_position, spatial_world_position, spatial_reservoir.sample_point_world_position, spatial_reservoir.sample_point_world_normal ); - if jacobian > 10.0 || jacobian < 0.1 { - return empty_reservoir(); - } - spatial_reservoir.unbiased_contribution_weight *= jacobian; spatial_reservoir.unbiased_contribution_weight *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); @@ -187,9 +183,11 @@ fn jacobian( let q = spatial_world_position - sample_point_world_position; let rl = length(r); let ql = length(q); + let rl2 = min(rl * rl, 500.0); // Clamping is biased, but decreases noise + let ql2 = min(ql * ql, 500.0); let phi_r = saturate(dot(r / rl, sample_point_world_normal)); let phi_q = saturate(dot(q / ql, sample_point_world_normal)); - let jacobian = (phi_r * ql * ql) / (phi_q * rl * rl); + let jacobian = (phi_r * ql2) / (phi_q * rl2); return select(jacobian, 0.0, isinf(jacobian) || isnan(jacobian)); } From b8438bede7f810ec775f7dd5ce7228aee608a605 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Tue, 22 Jul 2025 23:29:34 -0400 Subject: [PATCH 2/7] Release notes --- release-content/release-notes/bevy_solari.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/release-notes/bevy_solari.md b/release-content/release-notes/bevy_solari.md index e7c25e3c8e6dc..22417faa320e4 100644 --- a/release-content/release-notes/bevy_solari.md +++ b/release-content/release-notes/bevy_solari.md @@ -1,7 +1,7 @@ --- title: Initial raytraced lighting progress (bevy_solari) authors: ["@JMS55"] -pull_requests: [19058, 19620, 19790, 20020, 20113, 20213] +pull_requests: [19058, 19620, 19790, 20020, 20113, 20213, 20259] --- (TODO: Embed solari example screenshot here) From a83c266ac1a57abfa6e38c23400512b2da4e1efe Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Tue, 22 Jul 2025 23:40:20 -0400 Subject: [PATCH 3/7] Fmt --- crates/bevy_solari/src/realtime/restir_di.wgsl | 2 +- crates/bevy_solari/src/realtime/restir_gi.wgsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_di.wgsl b/crates/bevy_solari/src/realtime/restir_di.wgsl index 175b9ded96c09..ce81a8f4b3df1 100644 --- a/crates/bevy_solari/src/realtime/restir_di.wgsl +++ b/crates/bevy_solari/src/realtime/restir_di.wgsl @@ -92,7 +92,7 @@ fn spatial_and_shade(@builtin(global_invocation_id) global_id: vec3) { textureStore(view_output, global_id.xy, vec4(pixel_color, 1.0)); } -fn generate_initial_reservoir(world_position: vec3, world_normal: vec3, diffuse_brdf: vec3, workgroup_id: vec2, rng: ptr) -> Reservoir{ +fn generate_initial_reservoir(world_position: vec3, world_normal: vec3, diffuse_brdf: vec3, workgroup_id: vec2, rng: ptr) -> Reservoir { var workgroup_rng = (workgroup_id.x * 5782582u) + workgroup_id.y; let light_tile_start = rand_range_u(128u, &workgroup_rng) * 1024u; diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 607040567502f..6c638e6db36c6 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -83,7 +83,7 @@ fn spatial_and_shade(@builtin(global_invocation_id) global_id: vec3) { textureStore(view_output, global_id.xy, pixel_color); } -fn generate_initial_reservoir(world_position: vec3, world_normal: vec3, rng: ptr) -> Reservoir{ +fn generate_initial_reservoir(world_position: vec3, world_normal: vec3, rng: ptr) -> Reservoir { var reservoir = empty_reservoir(); let ray_direction = sample_uniform_hemisphere(world_normal, rng); From 8f168153b4fbd27281557a02817bcb86126483c2 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 23 Jul 2025 11:02:16 -0400 Subject: [PATCH 4/7] Go back to rejecting jacobian, but with a smaller threshold --- crates/bevy_solari/src/realtime/restir_gi.wgsl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 6c638e6db36c6..a1fcd42d944ec 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -155,12 +155,16 @@ 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.viewport.z); var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; - spatial_reservoir.unbiased_contribution_weight *= jacobian( + let jacobian = jacobian( world_position, spatial_world_position, spatial_reservoir.sample_point_world_position, spatial_reservoir.sample_point_world_normal ); + if jacobian < 1.0 / 3.0 || jacobian > 3.0 { + return empty_reservoir(); + } + spatial_reservoir.unbiased_contribution_weight *= jacobian; spatial_reservoir.unbiased_contribution_weight *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); @@ -183,11 +187,9 @@ fn jacobian( let q = spatial_world_position - sample_point_world_position; let rl = length(r); let ql = length(q); - let rl2 = min(rl * rl, 500.0); // Clamping is biased, but decreases noise - let ql2 = min(ql * ql, 500.0); let phi_r = saturate(dot(r / rl, sample_point_world_normal)); let phi_q = saturate(dot(q / ql, sample_point_world_normal)); - let jacobian = (phi_r * ql2) / (phi_q * rl2); + let jacobian = (phi_r * ql * ql) / (phi_q * rl * rl); return select(jacobian, 0.0, isinf(jacobian) || isnan(jacobian)); } From ff81d9ba7917d742d03361e0539bc66378e32036 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 23 Jul 2025 17:11:24 -0400 Subject: [PATCH 5/7] Fix error message --- crates/bevy_solari/src/scene/binder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_solari/src/scene/binder.rs b/crates/bevy_solari/src/scene/binder.rs index 4e75e7db6b3ce..0685c1dcf1acf 100644 --- a/crates/bevy_solari/src/scene/binder.rs +++ b/crates/bevy_solari/src/scene/binder.rs @@ -363,7 +363,7 @@ struct GpuLightSource { impl GpuLightSource { fn new_emissive_mesh_light(instance_id: u32, triangle_count: u32) -> GpuLightSource { if triangle_count > u16::MAX as u32 { - panic!("Too triangles in an emissive mesh, maximum is 65535."); + panic!("Too many triangles ({triangle_count}) in an emissive mesh, maximum is 65535."); } Self { From 9be8ac4c612da8210cf5d5b01da128435eb4270f Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 25 Jul 2025 10:00:31 -0400 Subject: [PATCH 6/7] Balance heuristic for spatial GI resampling --- .../bevy_solari/src/realtime/restir_di.wgsl | 3 +- .../bevy_solari/src/realtime/restir_gi.wgsl | 187 +++++++++++++----- 2 files changed, 139 insertions(+), 51 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_di.wgsl b/crates/bevy_solari/src/realtime/restir_di.wgsl index 272b01ae4d534..9b9899464402d 100644 --- a/crates/bevy_solari/src/realtime/restir_di.wgsl +++ b/crates/bevy_solari/src/realtime/restir_di.wgsl @@ -195,7 +195,7 @@ fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3< } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { - var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS, rng); + var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS - 1.0, rng) + 1.0; spatial_id = clamp(spatial_id, vec2(0.0), view.viewport.zw - 1.0); return vec2(spatial_id); } @@ -266,7 +266,6 @@ fn merge_reservoirs( diffuse_brdf: vec3, rng: ptr, ) -> ReservoirMergeResult { - // TODO: Balance heuristic MIS weights let mis_weight_denominator = 1.0 / (canonical_reservoir.confidence_weight + other_reservoir.confidence_weight); let canonical_mis_weight = canonical_reservoir.confidence_weight * mis_weight_denominator; diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 9c8f052d2f1ed..8c8980162d87d 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -44,9 +44,9 @@ fn initial_and_temporal(@builtin(global_invocation_id) global_id: vec3) { let initial_reservoir = generate_initial_reservoir(world_position, world_normal, &rng); let temporal_reservoir = load_temporal_reservoir(global_id.xy, depth, world_position, world_normal); - let merge_result = merge_reservoirs(initial_reservoir, temporal_reservoir, vec3(1.0), vec3(1.0), &rng); + let combined_reservoir = merge_reservoirs(initial_reservoir, temporal_reservoir, &rng); - gi_reservoirs_b[pixel_index] = merge_result.merged_reservoir; + gi_reservoirs_b[pixel_index] = combined_reservoir; } @compute @workgroup_size(8, 8, 1) @@ -68,12 +68,9 @@ fn spatial_and_shade(@builtin(global_invocation_id) global_id: vec3) { let diffuse_brdf = base_color / PI; let input_reservoir = gi_reservoirs_b[pixel_index]; - let spatial_reservoir = load_spatial_reservoir(global_id.xy, depth, world_position, world_normal, &rng); - - let input_factor = dot(normalize(input_reservoir.sample_point_world_position - world_position), world_normal) * diffuse_brdf; - let spatial_factor = dot(normalize(spatial_reservoir.sample_point_world_position - world_position), world_normal) * diffuse_brdf; - - let merge_result = merge_reservoirs(input_reservoir, spatial_reservoir, input_factor, spatial_factor, &rng); + let spatial = load_spatial_reservoir(global_id.xy, depth, world_position, world_normal, &rng); + let merge_result = merge_reservoirs_spatial(input_reservoir, world_position, world_normal, diffuse_brdf, + spatial.reservoir, spatial.world_position, spatial.world_normal, spatial.diffuse_brdf, &rng); let combined_reservoir = merge_result.merged_reservoir; gi_reservoirs_a[pixel_index] = combined_reservoir; @@ -141,50 +138,46 @@ fn load_temporal_reservoir(pixel_id: vec2, depth: f32, world_position: vec3 return temporal_reservoir; } -fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3, world_normal: vec3, rng: ptr) -> Reservoir { +struct SpatialInfo { + reservoir: Reservoir, + world_position: vec3, + world_normal: vec3, + diffuse_brdf: vec3, +} + +fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3, world_normal: vec3, rng: ptr) -> SpatialInfo { let spatial_pixel_id = get_neighbor_pixel_id(pixel_id, rng); let spatial_depth = textureLoad(depth_buffer, spatial_pixel_id, 0); let spatial_gpixel = textureLoad(gbuffer, spatial_pixel_id, 0); let spatial_world_position = reconstruct_world_position(spatial_pixel_id, spatial_depth); let spatial_world_normal = octahedral_decode(unpack_24bit_normal(spatial_gpixel.a)); + let spatial_base_color = pow(unpack4x8unorm(spatial_gpixel.r).rgb, vec3(2.2)); + let spatial_diffuse_brdf = spatial_base_color / PI; if pixel_dissimilar(depth, world_position, spatial_world_position, world_normal, spatial_world_normal) { - return empty_reservoir(); + return SpatialInfo(empty_reservoir(), spatial_world_position, spatial_world_normal, spatial_diffuse_brdf); } let spatial_pixel_index = spatial_pixel_id.x + spatial_pixel_id.y * u32(view.viewport.z); - var spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; + let spatial_reservoir = gi_reservoirs_b[spatial_pixel_index]; - let jacobian = jacobian( - world_position, - spatial_world_position, - spatial_reservoir.sample_point_world_position, - spatial_reservoir.sample_point_world_normal - ); - if jacobian < 1.0 / 3.0 || jacobian > 3.0 { - return empty_reservoir(); - } - spatial_reservoir.unbiased_contribution_weight *= jacobian; - - spatial_reservoir.unbiased_contribution_weight *= trace_point_visibility(world_position, spatial_reservoir.sample_point_world_position); - - return spatial_reservoir; + return SpatialInfo(spatial_reservoir, spatial_world_position, spatial_world_normal, spatial_diffuse_brdf); } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { - var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS, rng); + var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS - 1.0, rng) + 1.0; spatial_id = clamp(spatial_id, vec2(0.0), view.viewport.zw - 1.0); return vec2(spatial_id); } fn jacobian( - world_position: vec3, - spatial_world_position: vec3, + new_world_position: vec3, + original_world_position: vec3, sample_point_world_position: vec3, sample_point_world_normal: vec3, ) -> f32 { - let r = world_position - sample_point_world_position; - let q = spatial_world_position - sample_point_world_position; + let r = new_world_position - sample_point_world_position; + let q = original_world_position - sample_point_world_position; let rl = length(r); let ql = length(q); let phi_r = saturate(dot(r / rl, sample_point_world_normal)); @@ -256,34 +249,22 @@ fn empty_reservoir() -> Reservoir { ); } -struct ReservoirMergeResult { - merged_reservoir: Reservoir, - selected_sample_radiance: vec3, -} - fn merge_reservoirs( canonical_reservoir: Reservoir, other_reservoir: Reservoir, - canonical_factor: vec3, - other_factor: vec3, rng: ptr, -) -> ReservoirMergeResult { +) -> Reservoir { var combined_reservoir = empty_reservoir(); combined_reservoir.confidence_weight = canonical_reservoir.confidence_weight + other_reservoir.confidence_weight; - if combined_reservoir.confidence_weight == 0.0 { return ReservoirMergeResult(combined_reservoir, vec3(0.0)); } - - // TODO: Balance heuristic MIS weights - let mis_weight_denominator = 1.0 / combined_reservoir.confidence_weight; + let mis_weight_denominator = select(0.0, 1.0 / combined_reservoir.confidence_weight, combined_reservoir.confidence_weight > 0.0); let canonical_mis_weight = canonical_reservoir.confidence_weight * mis_weight_denominator; - let canonical_radiance = canonical_reservoir.radiance * canonical_factor; - let canonical_target_function = luminance(canonical_radiance); + let canonical_target_function = luminance(canonical_reservoir.radiance); let canonical_resampling_weight = canonical_mis_weight * (canonical_target_function * canonical_reservoir.unbiased_contribution_weight); let other_mis_weight = other_reservoir.confidence_weight * mis_weight_denominator; - let other_radiance = other_reservoir.radiance * other_factor; - let other_target_function = luminance(other_radiance); + let other_target_function = luminance(other_reservoir.radiance); let other_resampling_weight = other_mis_weight * (other_target_function * other_reservoir.unbiased_contribution_weight); combined_reservoir.weight_sum = canonical_resampling_weight + other_resampling_weight; @@ -295,8 +276,6 @@ fn merge_reservoirs( let inverse_target_function = select(0.0, 1.0 / other_target_function, other_target_function > 0.0); combined_reservoir.unbiased_contribution_weight = combined_reservoir.weight_sum * inverse_target_function; - - return ReservoirMergeResult(combined_reservoir, other_radiance); } else { combined_reservoir.sample_point_world_position = canonical_reservoir.sample_point_world_position; combined_reservoir.sample_point_world_normal = canonical_reservoir.sample_point_world_normal; @@ -304,7 +283,117 @@ fn merge_reservoirs( let inverse_target_function = select(0.0, 1.0 / canonical_target_function, canonical_target_function > 0.0); combined_reservoir.unbiased_contribution_weight = combined_reservoir.weight_sum * inverse_target_function; + } + + return combined_reservoir; +} + +struct ReservoirMergeResult { + merged_reservoir: Reservoir, + selected_sample_radiance: vec3, +} + +fn merge_reservoirs_spatial( + canonical_reservoir: Reservoir, + canonical_world_position: vec3, + canonical_world_normal: vec3, + canonical_diffuse_brdf: vec3, + other_reservoir: Reservoir, + other_world_position: vec3, + other_world_normal: vec3, + other_diffuse_brdf: vec3, + rng: ptr, +) -> ReservoirMergeResult { + // Radiances for resampling + let canonical_sample_radiance = + canonical_reservoir.radiance * + saturate(dot(normalize(canonical_reservoir.sample_point_world_position - canonical_world_position), canonical_world_normal)) * + canonical_diffuse_brdf; + let other_sample_radiance = + other_reservoir.radiance * + saturate(dot(normalize(other_reservoir.sample_point_world_position - canonical_world_position), canonical_world_normal)) * + canonical_diffuse_brdf * + trace_point_visibility(canonical_world_position, other_reservoir.sample_point_world_position); + + // Target functions for resampling and MIS + let canonical_target_function_canonical_sample = luminance(canonical_sample_radiance); + let canonical_target_function_other_sample = luminance(other_sample_radiance); + + // Extra target functions for MIS + let other_target_function_canonical_sample = luminance( + canonical_reservoir.radiance * + saturate(dot(normalize(canonical_reservoir.sample_point_world_position - other_world_position), other_world_normal)) * + other_diffuse_brdf + ); + let other_target_function_other_sample = luminance( + other_reservoir.radiance * + saturate(dot(normalize(other_reservoir.sample_point_world_position - other_world_position), other_world_normal)) * + other_diffuse_brdf + ); + + // Jacobians for resampling and MIS + let canonical_target_function_other_sample_jacobian = jacobian( + canonical_world_position, + other_world_position, + other_reservoir.sample_point_world_position, + other_reservoir.sample_point_world_normal + ); + let other_target_function_canonical_sample_jacobian = jacobian( + other_world_position, + canonical_world_position, + canonical_reservoir.sample_point_world_position, + canonical_reservoir.sample_point_world_normal + ); + + // Resampling weight for canonical sample + let canonical_sample_mis_weight = balance_heuristic( + canonical_reservoir.confidence_weight * canonical_target_function_canonical_sample, + other_reservoir.confidence_weight * other_target_function_canonical_sample * other_target_function_canonical_sample_jacobian, + ); + let canonical_sample_resampling_weight = canonical_sample_mis_weight * + canonical_target_function_canonical_sample * + canonical_reservoir.unbiased_contribution_weight; + + // Resampling weight for other sample + let other_sample_mis_weight = balance_heuristic( + other_reservoir.confidence_weight * other_target_function_other_sample, + canonical_reservoir.confidence_weight * canonical_target_function_other_sample * canonical_target_function_other_sample_jacobian, + ); + let other_sample_resampling_weight = other_sample_mis_weight * + canonical_target_function_other_sample * + other_reservoir.unbiased_contribution_weight * + canonical_target_function_other_sample_jacobian; + + // Perform resampling + var combined_reservoir = empty_reservoir(); + combined_reservoir.confidence_weight = canonical_reservoir.confidence_weight + other_reservoir.confidence_weight; + combined_reservoir.weight_sum = canonical_sample_resampling_weight + other_sample_resampling_weight; + + if rand_f(rng) < other_sample_resampling_weight / combined_reservoir.weight_sum { + combined_reservoir.sample_point_world_position = other_reservoir.sample_point_world_position; + combined_reservoir.sample_point_world_normal = other_reservoir.sample_point_world_normal; + combined_reservoir.radiance = other_reservoir.radiance; + + let inverse_target_function = select(0.0, 1.0 / canonical_target_function_other_sample, canonical_target_function_other_sample > 0.0); + combined_reservoir.unbiased_contribution_weight = combined_reservoir.weight_sum * inverse_target_function; + + return ReservoirMergeResult(combined_reservoir, other_sample_radiance); + } else { + combined_reservoir.sample_point_world_position = canonical_reservoir.sample_point_world_position; + combined_reservoir.sample_point_world_normal = canonical_reservoir.sample_point_world_normal; + combined_reservoir.radiance = canonical_reservoir.radiance; + + let inverse_target_function = select(0.0, 1.0 / canonical_target_function_canonical_sample, canonical_target_function_canonical_sample > 0.0); + combined_reservoir.unbiased_contribution_weight = combined_reservoir.weight_sum * inverse_target_function; + + return ReservoirMergeResult(combined_reservoir, canonical_sample_radiance); + } +} - return ReservoirMergeResult(combined_reservoir, canonical_radiance); +fn balance_heuristic(x: f32, y: f32) -> f32 { + let sum = x + y; + if sum == 0.0 { + return 0.0; } + return x / sum; } From 695e520547575e2c1a4e0aabeb4e7e195f99effe Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Fri, 25 Jul 2025 10:08:11 -0400 Subject: [PATCH 7/7] Revert neighbor bias --- crates/bevy_solari/src/realtime/restir_di.wgsl | 2 +- crates/bevy_solari/src/realtime/restir_gi.wgsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_solari/src/realtime/restir_di.wgsl b/crates/bevy_solari/src/realtime/restir_di.wgsl index 9b9899464402d..e3077e525e55c 100644 --- a/crates/bevy_solari/src/realtime/restir_di.wgsl +++ b/crates/bevy_solari/src/realtime/restir_di.wgsl @@ -195,7 +195,7 @@ fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3< } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { - var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS - 1.0, rng) + 1.0; + var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS, rng); spatial_id = clamp(spatial_id, vec2(0.0), view.viewport.zw - 1.0); return vec2(spatial_id); } diff --git a/crates/bevy_solari/src/realtime/restir_gi.wgsl b/crates/bevy_solari/src/realtime/restir_gi.wgsl index 8c8980162d87d..3a74411d12a96 100644 --- a/crates/bevy_solari/src/realtime/restir_gi.wgsl +++ b/crates/bevy_solari/src/realtime/restir_gi.wgsl @@ -165,7 +165,7 @@ fn load_spatial_reservoir(pixel_id: vec2, depth: f32, world_position: vec3< } fn get_neighbor_pixel_id(center_pixel_id: vec2, rng: ptr) -> vec2 { - var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS - 1.0, rng) + 1.0; + var spatial_id = vec2(center_pixel_id) + sample_disk(SPATIAL_REUSE_RADIUS_PIXELS, rng); spatial_id = clamp(spatial_id, vec2(0.0), view.viewport.zw - 1.0); return vec2(spatial_id); }