From c961568b969dc138e912b844b4d9949b05558fa4 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 19 Jul 2024 16:07:40 -0400 Subject: [PATCH] render: update the shadow filting poisson disc when shadow settings are modified --- lyra-game/src/render/graph/passes/shadows.rs | 49 ++++++++++---------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/lyra-game/src/render/graph/passes/shadows.rs b/lyra-game/src/render/graph/passes/shadows.rs index e4e1b61..cd217e7 100644 --- a/lyra-game/src/render/graph/passes/shadows.rs +++ b/lyra-game/src/render/graph/passes/shadows.rs @@ -12,7 +12,7 @@ use lyra_ecs::{ use lyra_game_derive::RenderGraphLabel; use lyra_math::{Angle, Transform}; use rustc_hash::FxHashMap; -use tracing::warn; +use tracing::{debug, warn}; use wgpu::util::DeviceExt; use crate::render::{ @@ -356,10 +356,8 @@ impl ShadowMapsPass { /// Generate and write a Poisson disc to `buffer` with `num_pcf_samples.pow(2)` amount of points. fn write_poisson_disc(&self, queue: &wgpu::Queue, buffer: &wgpu::Buffer, num_samples: u32) { - //let num_points = num_samples.pow(2); let num_floats = num_samples * 2; // points are vec2f let min_dist = (num_floats as f32).sqrt() / num_floats as f32; - //let min_dist = (num_samples as f32).sqrt() / num_samples as f32; let mut points = vec![]; // use a while loop to ensure that the correct number of floats is created @@ -439,12 +437,11 @@ impl Node for ShadowMapsPass { Some(SlotValue::Buffer(Arc::new(settings_buffer))), ); - let def_settings = ShadowSettings::default(); node.add_buffer_slot( ShadowMapsPassSlots::PcfPoissonDiscBuffer, SlotAttribute::Output, Some(SlotValue::Buffer(Arc::new( - self.create_poisson_disc_buffer(device, "buffer_poisson_disc_pcf", def_settings.pcf_samples_num), + self.create_poisson_disc_buffer(device, "buffer_poisson_disc_pcf", PCF_SAMPLES_NUM_MAX), ))), ); @@ -452,7 +449,7 @@ impl Node for ShadowMapsPass { ShadowMapsPassSlots::PcssPoissonDiscBuffer, SlotAttribute::Output, Some(SlotValue::Buffer(Arc::new( - self.create_poisson_disc_buffer(device, "buffer_poisson_disc_pcss", def_settings.pcss_blocker_search_samples), + self.create_poisson_disc_buffer(device, "buffer_poisson_disc_pcss", PCSS_SAMPLES_NUM_MAX), ))), ); @@ -465,25 +462,26 @@ impl Node for ShadowMapsPass { world: &mut lyra_ecs::World, context: &mut crate::render::graph::RenderGraphContext, ) { - { - // TODO: Update the poisson disc every time the PCF sampling point number changed - if !world.has_resource::() { - let def_settings = ShadowSettings::default(); - let buffer = graph.slot_value(ShadowMapsPassSlots::PcfPoissonDiscBuffer) - .unwrap().as_buffer().unwrap(); - self.write_poisson_disc(&context.queue, &buffer, def_settings.pcf_samples_num); + world.add_resource_default_if_absent::(); + if world.has_resource_changed::() { + debug!("Detected change in ShadowSettings, recreating poisson disks"); - let buffer = graph.slot_value(ShadowMapsPassSlots::PcssPoissonDiscBuffer) - .unwrap().as_buffer().unwrap(); - self.write_poisson_disc(&context.queue, &buffer, def_settings.pcss_blocker_search_samples); - } + let settings = world.get_resource::(); + // convert to uniform now since the from impl limits to max values + let uniform = ShadowSettingsUniform::from(*settings); + + let buffer = graph.slot_value(ShadowMapsPassSlots::PcfPoissonDiscBuffer) + .unwrap().as_buffer().unwrap(); + self.write_poisson_disc(&context.queue, &buffer, uniform.pcf_samples_num); + + let buffer = graph.slot_value(ShadowMapsPassSlots::PcssPoissonDiscBuffer) + .unwrap().as_buffer().unwrap(); + self.write_poisson_disc(&context.queue, &buffer, uniform.pcss_blocker_search_samples); - // TODO: only write buffer on changes to resource - let shadow_settings = world.get_resource_or_default::(); context.queue_buffer_write_with( ShadowMapsPassSlots::ShadowSettingsUniform, 0, - ShadowSettingsUniform::from(*shadow_settings), + uniform, ); } @@ -811,12 +809,12 @@ impl LightShadowMapAtlas { pub struct ShadowSettings { /// How many PCF filtering samples are used per dimension. /// - /// A value of 16 is common. + /// A value of 25 is common, this is maxed to 128. pub pcf_samples_num: u32, /// How many samples are used for the PCSS blocker search step. /// /// Multiple samples are required to avoid holes int he penumbra due to missing blockers. - /// A value of 16 is common. + /// A value of 25 is common, this is maxed to 128. pub pcss_blocker_search_samples: u32, } @@ -829,6 +827,9 @@ impl Default for ShadowSettings { } } +const PCF_SAMPLES_NUM_MAX: u32 = 128; +const PCSS_SAMPLES_NUM_MAX: u32 = 128; + /// Uniform version of [`ShadowSettings`] #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] @@ -840,8 +841,8 @@ struct ShadowSettingsUniform { impl From for ShadowSettingsUniform { fn from(value: ShadowSettings) -> Self { Self { - pcf_samples_num: value.pcf_samples_num, - pcss_blocker_search_samples: value.pcss_blocker_search_samples, + pcf_samples_num: value.pcf_samples_num.min(PCF_SAMPLES_NUM_MAX), + pcss_blocker_search_samples: value.pcss_blocker_search_samples.min(PCSS_SAMPLES_NUM_MAX), } } }