render: improve shadow settings to make it possible to switch between PCF, PCSS, hardware 2x2 PCF, or disable filtering all together
This commit is contained in:
parent
c961568b96
commit
c91ee67961
|
@ -494,27 +494,8 @@ impl Node for ShadowMapsPass {
|
|||
// use a queue for storing atlas ids to add to entities after the entities are iterated
|
||||
let mut index_components_queue = VecDeque::new();
|
||||
|
||||
/* for (entity, pos, (has_dir, has_point)) in world.view_iter::<(Entities, &Transform, Or<Has<DirectionalLight>, Has<PointLight>>)>() {
|
||||
if !self.depth_maps.contains_key(&entity) {
|
||||
// TODO: calculate far plane
|
||||
let (light_type, far_plane) = if has_dir.is_some() {
|
||||
(LightType::Directional, 45.0)
|
||||
} else if has_point.is_some() {
|
||||
(LightType::Point, 45.0)
|
||||
} else {
|
||||
todo!("Spot lights")
|
||||
};
|
||||
|
||||
// TODO: dont pack the textures as they're added
|
||||
let atlas_index =
|
||||
self.create_depth_map(&context.queue, light_type, entity, *pos, far_plane);
|
||||
index_components_queue.push_back((entity, atlas_index));
|
||||
}
|
||||
} */
|
||||
|
||||
for (entity, pos, _) in world.view_iter::<(Entities, &Transform, Has<DirectionalLight>)>() {
|
||||
if !self.depth_maps.contains_key(&entity) {
|
||||
// TODO: dont pack the textures as they're added
|
||||
let atlas_index = self.create_depth_map(
|
||||
&context.queue,
|
||||
LightType::Directional,
|
||||
|
@ -528,7 +509,6 @@ impl Node for ShadowMapsPass {
|
|||
|
||||
for (entity, pos, _) in world.view_iter::<(Entities, &Transform, Has<PointLight>)>() {
|
||||
if !self.depth_maps.contains_key(&entity) {
|
||||
// TODO: dont pack the textures as they're added
|
||||
let atlas_index =
|
||||
self.create_depth_map(&context.queue, LightType::Point, entity, *pos, 30.0);
|
||||
index_components_queue.push_back((entity, atlas_index));
|
||||
|
@ -727,7 +707,6 @@ fn light_shadow_pass_impl<'a>(
|
|||
}
|
||||
let buffers = buffers.unwrap();
|
||||
|
||||
//let uniform_index = light_uniforms_buffer.offset_of(light_depth_map.uniform_index[0]) as u32;
|
||||
pass.set_bind_group(0, &uniforms_bind_group, &[]);
|
||||
|
||||
// Get the bindgroup for job's transform and bind to it using an offset.
|
||||
|
@ -805,8 +784,19 @@ impl LightShadowMapAtlas {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
pub enum ShadowFilteringMode {
|
||||
None,
|
||||
/// Uses hardware features for 2x2 PCF.
|
||||
Pcf2x2,
|
||||
Pcf,
|
||||
#[default]
|
||||
Pcss,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ShadowSettings {
|
||||
pub filtering_mode: ShadowFilteringMode,
|
||||
/// How many PCF filtering samples are used per dimension.
|
||||
///
|
||||
/// A value of 25 is common, this is maxed to 128.
|
||||
|
@ -821,8 +811,9 @@ pub struct ShadowSettings {
|
|||
impl Default for ShadowSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pcf_samples_num: 64,
|
||||
pcss_blocker_search_samples: 36,
|
||||
filtering_mode: ShadowFilteringMode::default(),
|
||||
pcf_samples_num: 25,
|
||||
pcss_blocker_search_samples: 25,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -830,19 +821,34 @@ 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`].
|
||||
///
|
||||
/// If `pcf_samples_num` is set to zero, PCF and PCSS will be disabled.
|
||||
/// If `pcf_samples_num` is set to 2, ONLY hardware 2x2 PCF will be used.
|
||||
/// If `pcss_blocker_search_samples` is set to zero, PCSS will be disabled.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
struct ShadowSettingsUniform {
|
||||
//use_pcf_hardware_2x2: u32,
|
||||
pcf_samples_num: u32,
|
||||
pcss_blocker_search_samples: u32,
|
||||
}
|
||||
|
||||
impl From<ShadowSettings> for ShadowSettingsUniform {
|
||||
fn from(value: ShadowSettings) -> Self {
|
||||
let raw_pcf_samples = value.pcf_samples_num.min(PCF_SAMPLES_NUM_MAX);
|
||||
let raw_pcss_samples = value.pcss_blocker_search_samples.min(PCSS_SAMPLES_NUM_MAX);
|
||||
|
||||
let (pcf_samples, pcss_samples) = match value.filtering_mode {
|
||||
ShadowFilteringMode::None => (0, 0),
|
||||
ShadowFilteringMode::Pcf2x2 => (2, 0),
|
||||
ShadowFilteringMode::Pcf => (raw_pcf_samples, 0),
|
||||
ShadowFilteringMode::Pcss => (raw_pcf_samples, raw_pcss_samples),
|
||||
};
|
||||
|
||||
Self {
|
||||
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),
|
||||
pcf_samples_num: pcf_samples,
|
||||
pcss_blocker_search_samples: pcss_samples,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,21 +257,29 @@ fn calc_shadow_dir_light(normal: vec3<f32>, light_dir: vec3<f32>, frag_pos_light
|
|||
// Remap xy to [0.0, 1.0]
|
||||
let xy_remapped = proj_coords.xy * 0.5 + 0.5;
|
||||
|
||||
// get the atlas frame in [0; 1] in the atlas texture
|
||||
// z is width, w is height
|
||||
var region_rect = vec4<f32>(f32(shadow_u.atlas_frame.x), f32(shadow_u.atlas_frame.y), f32(shadow_u.atlas_frame.width), f32(shadow_u.atlas_frame.height));
|
||||
region_rect /= f32(atlas_dimensions.x);
|
||||
let region_coords = vec2<f32>(
|
||||
mix(region_rect.x, region_rect.x + region_rect.z, xy_remapped.x),
|
||||
mix(region_rect.y, region_rect.y + region_rect.w, xy_remapped.y)
|
||||
);
|
||||
|
||||
// use a bias to avoid shadow acne
|
||||
let bias = 0.005;//max(0.05 * (1.0 - dot(normal, light_dir)), 0.005);
|
||||
let current_depth = proj_coords.z - bias;
|
||||
|
||||
//var shadow = pcf_dir_light(region_coords, current_depth, shadow_u, 1.0);
|
||||
var shadow = pcss_dir_light(xy_remapped, current_depth, shadow_u);
|
||||
var shadow = 0.0;
|
||||
if u_shadow_settings.pcf_samples_num > 0u && u_shadow_settings.pcss_blocker_search_samples > 0u {
|
||||
shadow = pcss_dir_light(xy_remapped, current_depth, shadow_u);
|
||||
}
|
||||
// hardware 2x2 PCF via camparison sampler
|
||||
else if u_shadow_settings.pcf_samples_num == 2u {
|
||||
let region_coords = to_atlas_frame_coords(shadow_u, xy_remapped);
|
||||
shadow = textureSampleCompare(t_shadow_maps_atlas, s_shadow_maps_atlas_compare, region_coords, current_depth);
|
||||
} else if u_shadow_settings.pcf_samples_num > 0u {
|
||||
let atlas_dimensions = textureDimensions(t_shadow_maps_atlas);
|
||||
// TODO: should texel size be using the entire atlas dimensions, or just the frame?
|
||||
let texel_size = 1.0 / f32(atlas_dimensions.x); // f32(shadow_u.atlas_frame.width)
|
||||
|
||||
shadow = pcf_dir_light(xy_remapped, current_depth, shadow_u, texel_size);
|
||||
} else { // pcf_samples_num == 0
|
||||
let region_coords = to_atlas_frame_coords(shadow_u, xy_remapped);
|
||||
let closest_depth = textureSampleLevel(t_shadow_maps_atlas, s_shadow_maps_atlas, region_coords, 0.0);
|
||||
shadow = select(1.0, 0.0, current_depth > closest_depth);
|
||||
}
|
||||
|
||||
// dont cast shadows outside the light's far plane
|
||||
if (proj_coords.z > 1.0) {
|
||||
|
|
Loading…
Reference in New Issue