Implement Shadows #24

Merged
SeanOMik merged 28 commits from feat/shadow-maps into main 2024-08-10 03:10:30 +00:00
1 changed files with 25 additions and 24 deletions
Showing only changes of commit c961568b96 - Show all commits

View File

@ -12,7 +12,7 @@ use lyra_ecs::{
use lyra_game_derive::RenderGraphLabel; use lyra_game_derive::RenderGraphLabel;
use lyra_math::{Angle, Transform}; use lyra_math::{Angle, Transform};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use tracing::warn; use tracing::{debug, warn};
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use crate::render::{ 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. /// 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) { 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 num_floats = num_samples * 2; // points are vec2f
let min_dist = (num_floats as f32).sqrt() / num_floats as f32; 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![]; let mut points = vec![];
// use a while loop to ensure that the correct number of floats is created // 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))), Some(SlotValue::Buffer(Arc::new(settings_buffer))),
); );
let def_settings = ShadowSettings::default();
node.add_buffer_slot( node.add_buffer_slot(
ShadowMapsPassSlots::PcfPoissonDiscBuffer, ShadowMapsPassSlots::PcfPoissonDiscBuffer,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(Arc::new( 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, ShadowMapsPassSlots::PcssPoissonDiscBuffer,
SlotAttribute::Output, SlotAttribute::Output,
Some(SlotValue::Buffer(Arc::new( 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, world: &mut lyra_ecs::World,
context: &mut crate::render::graph::RenderGraphContext, context: &mut crate::render::graph::RenderGraphContext,
) { ) {
{ world.add_resource_default_if_absent::<ShadowSettings>();
// TODO: Update the poisson disc every time the PCF sampling point number changed if world.has_resource_changed::<ShadowSettings>() {
if !world.has_resource::<ShadowSettings>() { debug!("Detected change in ShadowSettings, recreating poisson disks");
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);
let buffer = graph.slot_value(ShadowMapsPassSlots::PcssPoissonDiscBuffer) let settings = world.get_resource::<ShadowSettings>();
.unwrap().as_buffer().unwrap(); // convert to uniform now since the from impl limits to max values
self.write_poisson_disc(&context.queue, &buffer, def_settings.pcss_blocker_search_samples); 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::<ShadowSettings>();
context.queue_buffer_write_with( context.queue_buffer_write_with(
ShadowMapsPassSlots::ShadowSettingsUniform, ShadowMapsPassSlots::ShadowSettingsUniform,
0, 0,
ShadowSettingsUniform::from(*shadow_settings), uniform,
); );
} }
@ -811,12 +809,12 @@ impl LightShadowMapAtlas {
pub struct ShadowSettings { pub struct ShadowSettings {
/// How many PCF filtering samples are used per dimension. /// 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, pub pcf_samples_num: u32,
/// How many samples are used for the PCSS blocker search step. /// 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. /// 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, 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`] /// Uniform version of [`ShadowSettings`]
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
@ -840,8 +841,8 @@ struct ShadowSettingsUniform {
impl From<ShadowSettings> for ShadowSettingsUniform { impl From<ShadowSettings> for ShadowSettingsUniform {
fn from(value: ShadowSettings) -> Self { fn from(value: ShadowSettings) -> Self {
Self { Self {
pcf_samples_num: value.pcf_samples_num, pcf_samples_num: value.pcf_samples_num.min(PCF_SAMPLES_NUM_MAX),
pcss_blocker_search_samples: value.pcss_blocker_search_samples, pcss_blocker_search_samples: value.pcss_blocker_search_samples.min(PCSS_SAMPLES_NUM_MAX),
} }
} }
} }