Implement Shadows #24
|
@ -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::<ShadowSettings>() {
|
||||
let def_settings = ShadowSettings::default();
|
||||
world.add_resource_default_if_absent::<ShadowSettings>();
|
||||
if world.has_resource_changed::<ShadowSettings>() {
|
||||
debug!("Detected change in ShadowSettings, recreating poisson disks");
|
||||
|
||||
let settings = world.get_resource::<ShadowSettings>();
|
||||
// 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, def_settings.pcf_samples_num);
|
||||
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, def_settings.pcss_blocker_search_samples);
|
||||
}
|
||||
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(
|
||||
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<ShadowSettings> 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue