diff --git a/blade-helpers/src/hud.rs b/blade-helpers/src/hud.rs index 4d0579a0..8940825f 100644 --- a/blade-helpers/src/hud.rs +++ b/blade-helpers/src/hud.rs @@ -34,6 +34,9 @@ impl ExposeHud for blade_render::RayConfig { .logarithmic(true), ); ui.checkbox(&mut self.pairwise_mis, "Pairwise MIS"); + ui.add( + egui::widgets::Slider::new(&mut self.defensive_mis, 0.0..=1.0).text("Defensive MIS"), + ); } } diff --git a/blade-render/code/ray-trace.wgsl b/blade-render/code/ray-trace.wgsl index dccf8d47..93cacd15 100644 --- a/blade-render/code/ray-trace.wgsl +++ b/blade-render/code/ray-trace.wgsl @@ -39,8 +39,10 @@ struct MainParams { spatial_min_distance: i32, t_start: f32, use_pairwise_mis: u32, + defensive_mis: f32, use_motion_vectors: u32, temporal_accumulation_weight: f32, + pad: f32, grid_scale: vec2, } @@ -424,15 +426,18 @@ fn resample( if (parameters.use_pairwise_mis != 0u) { let canonical = base.canonical; let neighbor_history = min(neighbor.confidence, max_confidence); + let mis_scale = 1.0 / (base.accepted_count + parameters.defensive_mis); { // scoping this to hint the register allocation let t_canonical_at_neighbor = estimate_target_score_with_occlusion( other.surface, other.world_pos, canonical.selected_light_index, canonical.selected_uv, other_acs); - rr.mis_canonical = ratio(canonical.selected_target_score, t_canonical_at_neighbor.score) / base.accepted_count; + let r_canonical = ratio(canonical.history * canonical.selected_target_score / base.accepted_count, neighbor_history * t_canonical_at_neighbor.score); + rr.mis_canonical = mis_scale * (parameters.defensive_mis / base.accepted_count + r_canonical); } let t_neighbor_at_canonical = estimate_target_score_with_occlusion( base.surface, base.world_pos, neighbor.light_index, neighbor.light_uv, acc_struct); - rr.mis_sample = ratio(neighbor.target_score, t_neighbor_at_canonical.score) / base.accepted_count; + let r_neighbor = ratio(neighbor_history * neighbor.target_score, canonical.history * t_neighbor_at_canonical.score / base.accepted_count); + rr.mis_sample = mis_scale * r_neighbor; src.history = neighbor_history; src.selected_light_index = neighbor.light_index; @@ -523,15 +528,16 @@ fn resample_temporal( let prev_world_pos = prev_camera.position + tr.surface.depth * prev_dir; let other = PixelCache(tr.surface, tr.reservoir, prev_world_pos); let rr = resample(&reservoir, &color_and_weight, base, other, prev_acc_struct, parameters.temporal_tap_confidence); + let mis_canonical = rr.mis_canonical; if (WRITE_DEBUG_IMAGE && debug.view_mode == DebugMode_TemporalMatch) { textureStore(out_debug, cur_pixel, vec4(1.0)); } if (WRITE_DEBUG_IMAGE && debug.view_mode == DebugMode_TemporalMisCanonical) { - textureStore(out_debug, cur_pixel, vec4(rr.mis_canonical)); + textureStore(out_debug, cur_pixel, vec4(mis_canonical)); } - return finalize_resampling(&reservoir, &color_and_weight, base, rr.mis_canonical); + return finalize_resampling(&reservoir, &color_and_weight, base, mis_canonical); } fn resample_spatial( diff --git a/blade-render/src/render/mod.rs b/blade-render/src/render/mod.rs index 4b18eecd..4dd56365 100644 --- a/blade-render/src/render/mod.rs +++ b/blade-render/src/render/mod.rs @@ -108,6 +108,7 @@ pub struct RayConfig { /// See "9.1 pairwise mis for robust reservoir reuse" /// "Correlations and Reuse for Fast and Accurate Physically Based Light Transport" pub pairwise_mis: bool, + pub defensive_mis: f32, } #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] @@ -374,8 +375,10 @@ struct MainParams { spatial_min_distance: u32, t_start: f32, use_pairwise_mis: u32, + defensive_mis: f32, use_motion_vectors: u32, temporal_accumulation_weight: f32, + pad: u32, grid_scale: [u32; 2], } @@ -1098,12 +1101,14 @@ impl Renderer { spatial_min_distance: ray_config.spatial_min_distance, t_start: ray_config.t_start, use_pairwise_mis: ray_config.pairwise_mis as u32, + defensive_mis: ray_config.defensive_mis, use_motion_vectors: (self.frame_scene_built == self.frame_index) as u32, temporal_accumulation_weight: if denoiser_config.enabled { denoiser_config.temporal_weight } else { 1.0 }, + pad: 0, grid_scale, }, acc_struct: self.acceleration_structure, diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 5ee2beca..c58c6a48 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -267,6 +267,7 @@ impl Example { group_mixer: 10, t_start: 0.1, pairwise_mis: true, + defensive_mis: 0.0, }, denoiser_config: blade_render::DenoiserConfig { enabled: true, diff --git a/src/lib.rs b/src/lib.rs index 774e5cea..72e0a2c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -487,11 +487,12 @@ impl Engine { temporal_tap: true, temporal_confidence: 10.0, spatial_taps: 1, - spatial_confidence: 5.0, + spatial_confidence: 10.0, spatial_min_distance: 2, group_mixer: 10, t_start: 0.01, pairwise_mis: true, + defensive_mis: 0.1, }, denoiser_config: blade_render::DenoiserConfig { enabled: true,