bevy_pbr2: Add support for configurable shadow map sizes (#2700)
# Objective Add support for configurable shadow map sizes ## Solution - Add `DirectionalLightShadowMap` and `PointLightShadowMap` resources, which just have size members, to the app world, and add `Extracted*` counterparts to the render world - Use the configured sizes when rendering shadow maps - Default sizes remain the same - 4096 for directional light shadow maps, 1024 for point light shadow maps (which are cube maps so 6 faces at 1024x1024 per light)
This commit is contained in:
parent
9898469e9e
commit
f368bf7fc7
@ -28,7 +28,9 @@ pub struct PbrPlugin;
|
|||||||
impl Plugin for PbrPlugin {
|
impl Plugin for PbrPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugin(StandardMaterialPlugin)
|
app.add_plugin(StandardMaterialPlugin)
|
||||||
.init_resource::<AmbientLight>();
|
.init_resource::<AmbientLight>()
|
||||||
|
.init_resource::<DirectionalLightShadowMap>()
|
||||||
|
.init_resource::<PointLightShadowMap>();
|
||||||
|
|
||||||
let render_app = app.sub_app(RenderApp);
|
let render_app = app.sub_app(RenderApp);
|
||||||
render_app
|
render_app
|
||||||
|
@ -49,6 +49,17 @@ impl PointLight {
|
|||||||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.5;
|
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PointLightShadowMap {
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PointLightShadowMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { size: 1024 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A Directional light.
|
/// A Directional light.
|
||||||
///
|
///
|
||||||
/// Directional lights don't exist in reality but they are a good
|
/// Directional lights don't exist in reality but they are a good
|
||||||
@ -113,6 +124,17 @@ impl DirectionalLight {
|
|||||||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
|
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DirectionalLightShadowMap {
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DirectionalLightShadowMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { size: 4096 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ambient light.
|
/// Ambient light.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AmbientLight {
|
pub struct AmbientLight {
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::{AmbientLight, DirectionalLight, ExtractedMeshes, MeshMeta, PbrShaders, PointLight};
|
use crate::{
|
||||||
|
AmbientLight, DirectionalLight, DirectionalLightShadowMap, ExtractedMeshes, MeshMeta,
|
||||||
|
PbrShaders, PointLight, PointLightShadowMap,
|
||||||
|
};
|
||||||
use bevy_core_pipeline::Transparent3dPhase;
|
use bevy_core_pipeline::Transparent3dPhase;
|
||||||
use bevy_ecs::{prelude::*, system::SystemState};
|
use bevy_ecs::{prelude::*, system::SystemState};
|
||||||
use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
|
use bevy_math::{const_vec3, Mat4, Vec3, Vec4};
|
||||||
@ -34,6 +37,8 @@ pub struct ExtractedPointLight {
|
|||||||
shadow_normal_bias: f32,
|
shadow_normal_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ExtractedPointLightShadowMap = PointLightShadowMap;
|
||||||
|
|
||||||
pub struct ExtractedDirectionalLight {
|
pub struct ExtractedDirectionalLight {
|
||||||
color: Color,
|
color: Color,
|
||||||
illuminance: f32,
|
illuminance: f32,
|
||||||
@ -43,6 +48,8 @@ pub struct ExtractedDirectionalLight {
|
|||||||
shadow_normal_bias: f32,
|
shadow_normal_bias: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ExtractedDirectionalLightShadowMap = DirectionalLightShadowMap;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, AsStd140, Default, Debug)]
|
#[derive(Copy, Clone, AsStd140, Default, Debug)]
|
||||||
pub struct GpuPointLight {
|
pub struct GpuPointLight {
|
||||||
@ -81,16 +88,8 @@ pub struct GpuLights {
|
|||||||
// NOTE: this must be kept in sync with the same constants in pbr.frag
|
// NOTE: this must be kept in sync with the same constants in pbr.frag
|
||||||
pub const MAX_POINT_LIGHTS: usize = 10;
|
pub const MAX_POINT_LIGHTS: usize = 10;
|
||||||
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1;
|
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1;
|
||||||
pub const POINT_SHADOW_SIZE: Extent3d = Extent3d {
|
pub const POINT_SHADOW_LAYERS: u32 = (6 * MAX_POINT_LIGHTS) as u32;
|
||||||
width: 1024,
|
pub const DIRECTIONAL_SHADOW_LAYERS: u32 = MAX_DIRECTIONAL_LIGHTS as u32;
|
||||||
height: 1024,
|
|
||||||
depth_or_array_layers: (6 * MAX_POINT_LIGHTS) as u32,
|
|
||||||
};
|
|
||||||
pub const DIRECTIONAL_SHADOW_SIZE: Extent3d = Extent3d {
|
|
||||||
width: 4096,
|
|
||||||
height: 4096,
|
|
||||||
depth_or_array_layers: MAX_DIRECTIONAL_LIGHTS as u32,
|
|
||||||
};
|
|
||||||
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
|
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
|
||||||
|
|
||||||
pub struct ShadowShaders {
|
pub struct ShadowShaders {
|
||||||
@ -222,6 +221,8 @@ impl FromWorld for ShadowShaders {
|
|||||||
pub fn extract_lights(
|
pub fn extract_lights(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
ambient_light: Res<AmbientLight>,
|
ambient_light: Res<AmbientLight>,
|
||||||
|
point_light_shadow_map: Res<PointLightShadowMap>,
|
||||||
|
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
||||||
point_lights: Query<(Entity, &PointLight, &GlobalTransform)>,
|
point_lights: Query<(Entity, &PointLight, &GlobalTransform)>,
|
||||||
directional_lights: Query<(Entity, &DirectionalLight, &GlobalTransform)>,
|
directional_lights: Query<(Entity, &DirectionalLight, &GlobalTransform)>,
|
||||||
) {
|
) {
|
||||||
@ -229,6 +230,10 @@ pub fn extract_lights(
|
|||||||
color: ambient_light.color,
|
color: ambient_light.color,
|
||||||
brightness: ambient_light.brightness,
|
brightness: ambient_light.brightness,
|
||||||
});
|
});
|
||||||
|
commands.insert_resource::<ExtractedPointLightShadowMap>(point_light_shadow_map.clone());
|
||||||
|
commands.insert_resource::<ExtractedDirectionalLightShadowMap>(
|
||||||
|
directional_light_shadow_map.clone(),
|
||||||
|
);
|
||||||
// This is the point light shadow map texel size for one face of the cube as a distance of 1.0
|
// This is the point light shadow map texel size for one face of the cube as a distance of 1.0
|
||||||
// world unit from the light.
|
// world unit from the light.
|
||||||
// point_light_texel_size = 2.0 * 1.0 * tan(PI / 4.0) / cube face width in texels
|
// point_light_texel_size = 2.0 * 1.0 * tan(PI / 4.0) / cube face width in texels
|
||||||
@ -236,7 +241,7 @@ pub fn extract_lights(
|
|||||||
// point_light_texel_size = 2.0 / cube face width in texels
|
// point_light_texel_size = 2.0 / cube face width in texels
|
||||||
// NOTE: When using various PCF kernel sizes, this will need to be adjusted, according to:
|
// NOTE: When using various PCF kernel sizes, this will need to be adjusted, according to:
|
||||||
// https://catlikecoding.com/unity/tutorials/custom-srp/point-and-spot-shadows/
|
// https://catlikecoding.com/unity/tutorials/custom-srp/point-and-spot-shadows/
|
||||||
let point_light_texel_size = 2.0 / POINT_SHADOW_SIZE.width as f32;
|
let point_light_texel_size = 2.0 / point_light_shadow_map.size as f32;
|
||||||
for (entity, point_light, transform) in point_lights.iter() {
|
for (entity, point_light, transform) in point_lights.iter() {
|
||||||
commands.get_or_spawn(entity).insert(ExtractedPointLight {
|
commands.get_or_spawn(entity).insert(ExtractedPointLight {
|
||||||
color: point_light.color,
|
color: point_light.color,
|
||||||
@ -265,7 +270,8 @@ pub fn extract_lights(
|
|||||||
directional_light.shadow_projection.top
|
directional_light.shadow_projection.top
|
||||||
- directional_light.shadow_projection.bottom,
|
- directional_light.shadow_projection.bottom,
|
||||||
);
|
);
|
||||||
let directional_light_texel_size = largest_dimension / DIRECTIONAL_SHADOW_SIZE.width as f32;
|
let directional_light_texel_size =
|
||||||
|
largest_dimension / directional_light_shadow_map.size as f32;
|
||||||
commands
|
commands
|
||||||
.get_or_spawn(entity)
|
.get_or_spawn(entity)
|
||||||
.insert(ExtractedDirectionalLight {
|
.insert(ExtractedDirectionalLight {
|
||||||
@ -366,6 +372,8 @@ pub fn prepare_lights(
|
|||||||
mut light_meta: ResMut<LightMeta>,
|
mut light_meta: ResMut<LightMeta>,
|
||||||
views: Query<Entity, With<RenderPhase<Transparent3dPhase>>>,
|
views: Query<Entity, With<RenderPhase<Transparent3dPhase>>>,
|
||||||
ambient_light: Res<ExtractedAmbientLight>,
|
ambient_light: Res<ExtractedAmbientLight>,
|
||||||
|
point_light_shadow_map: Res<ExtractedPointLightShadowMap>,
|
||||||
|
directional_light_shadow_map: Res<ExtractedDirectionalLightShadowMap>,
|
||||||
point_lights: Query<&ExtractedPointLight>,
|
point_lights: Query<&ExtractedPointLight>,
|
||||||
directional_lights: Query<&ExtractedDirectionalLight>,
|
directional_lights: Query<&ExtractedDirectionalLight>,
|
||||||
) {
|
) {
|
||||||
@ -380,7 +388,11 @@ pub fn prepare_lights(
|
|||||||
let point_light_depth_texture = texture_cache.get(
|
let point_light_depth_texture = texture_cache.get(
|
||||||
&render_device,
|
&render_device,
|
||||||
TextureDescriptor {
|
TextureDescriptor {
|
||||||
size: POINT_SHADOW_SIZE,
|
size: Extent3d {
|
||||||
|
width: point_light_shadow_map.size as u32,
|
||||||
|
height: point_light_shadow_map.size as u32,
|
||||||
|
depth_or_array_layers: POINT_SHADOW_LAYERS,
|
||||||
|
},
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: TextureDimension::D2,
|
dimension: TextureDimension::D2,
|
||||||
@ -392,7 +404,11 @@ pub fn prepare_lights(
|
|||||||
let directional_light_depth_texture = texture_cache.get(
|
let directional_light_depth_texture = texture_cache.get(
|
||||||
&render_device,
|
&render_device,
|
||||||
TextureDescriptor {
|
TextureDescriptor {
|
||||||
size: DIRECTIONAL_SHADOW_SIZE,
|
size: Extent3d {
|
||||||
|
width: directional_light_shadow_map.size as u32,
|
||||||
|
height: directional_light_shadow_map.size as u32,
|
||||||
|
depth_or_array_layers: DIRECTIONAL_SHADOW_LAYERS,
|
||||||
|
},
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: TextureDimension::D2,
|
dimension: TextureDimension::D2,
|
||||||
@ -451,8 +467,8 @@ pub fn prepare_lights(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: POINT_SHADOW_SIZE.width,
|
width: point_light_shadow_map.size as u32,
|
||||||
height: POINT_SHADOW_SIZE.height,
|
height: point_light_shadow_map.size as u32,
|
||||||
transform: view_translation * view_rotation,
|
transform: view_translation * view_rotation,
|
||||||
projection,
|
projection,
|
||||||
},
|
},
|
||||||
@ -537,8 +553,8 @@ pub fn prepare_lights(
|
|||||||
pass_name: format!("shadow pass directional light {}", i),
|
pass_name: format!("shadow pass directional light {}", i),
|
||||||
},
|
},
|
||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: DIRECTIONAL_SHADOW_SIZE.width,
|
width: directional_light_shadow_map.size as u32,
|
||||||
height: DIRECTIONAL_SHADOW_SIZE.height,
|
height: directional_light_shadow_map.size as u32,
|
||||||
transform: GlobalTransform::from_matrix(view.inverse()),
|
transform: GlobalTransform::from_matrix(view.inverse()),
|
||||||
projection,
|
projection,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user