Implement Shadows #24
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue