mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
Per-light toggleable shadow mapping (#3126)
# Objective Allow shadow mapping to be enabled/disabled per-light. ## Solution - NOTE: This PR is on top of https://github.com/bevyengine/bevy/pull/3072 - Add `shadows_enabled` boolean property to `PointLight` and `DirectionalLight` components. - Do not update the frusta for the light if shadows are disabled. - Do not check for visible entities for the light if shadows are disabled. - Do not fetch shadows for lights with shadows disabled. - I reworked a few types for clarity: `ViewLight` -> `ShadowView`, the bulk of `ViewLights` members -> `ViewShadowBindings`, the entities Vec in `ViewLights` -> `ViewLightEntities`, the uniform offset in `ViewLights` for `GpuLights` -> `ViewLightsUniformOffset` Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
2e79951659
commit
a7729319cc
5 changed files with 204 additions and 103 deletions
|
@ -33,6 +33,7 @@ pub struct PointLight {
|
|||
pub intensity: f32,
|
||||
pub range: f32,
|
||||
pub radius: f32,
|
||||
pub shadows_enabled: bool,
|
||||
pub shadow_depth_bias: f32,
|
||||
/// A bias applied along the direction of the fragment's surface normal. It is scaled to the
|
||||
/// shadow map's texel size so that it can be small close to the camera and gets larger further
|
||||
|
@ -48,6 +49,7 @@ impl Default for PointLight {
|
|||
intensity: 800.0, // Roughly a 60W non-halogen incandescent bulb
|
||||
range: 20.0,
|
||||
radius: 0.0,
|
||||
shadows_enabled: false,
|
||||
shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
|
||||
shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
|
||||
}
|
||||
|
@ -101,6 +103,7 @@ pub struct DirectionalLight {
|
|||
pub color: Color,
|
||||
/// Illuminance in lux
|
||||
pub illuminance: f32,
|
||||
pub shadows_enabled: bool,
|
||||
pub shadow_projection: OrthographicProjection,
|
||||
pub shadow_depth_bias: f32,
|
||||
/// A bias applied along the direction of the fragment's surface normal. It is scaled to the
|
||||
|
@ -114,6 +117,7 @@ impl Default for DirectionalLight {
|
|||
DirectionalLight {
|
||||
color: Color::rgb(1.0, 1.0, 1.0),
|
||||
illuminance: 100000.0,
|
||||
shadows_enabled: false,
|
||||
shadow_projection: OrthographicProjection {
|
||||
left: -size,
|
||||
right: size,
|
||||
|
@ -178,6 +182,13 @@ pub fn update_directional_light_frusta(
|
|||
mut views: Query<(&GlobalTransform, &DirectionalLight, &mut Frustum)>,
|
||||
) {
|
||||
for (transform, directional_light, mut frustum) in views.iter_mut() {
|
||||
// The frustum is used for culling meshes to the light for shadow mapping
|
||||
// so if shadow mapping is disabled for this light, then the frustum is
|
||||
// not needed.
|
||||
if !directional_light.shadows_enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
let view_projection = directional_light.shadow_projection.get_projection_matrix()
|
||||
* transform.compute_matrix().inverse();
|
||||
*frustum = Frustum::from_view_projection(
|
||||
|
@ -199,6 +210,13 @@ pub fn update_point_light_frusta(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
for (transform, point_light, mut cubemap_frusta) in views.iter_mut() {
|
||||
// The frusta are used for culling meshes to the light for shadow mapping
|
||||
// so if shadow mapping is disabled for this light, then the frusta are
|
||||
// not needed.
|
||||
if !point_light.shadows_enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ignore scale because we don't want to effectively scale light radius and range
|
||||
// by applying those as a view transform to shadow map rendering of objects
|
||||
// and ignore rotation because we want the shadow map projections to align with the axes
|
||||
|
@ -227,10 +245,12 @@ pub fn check_light_visibility(
|
|||
&mut CubemapVisibleEntities,
|
||||
Option<&RenderLayers>,
|
||||
)>,
|
||||
mut directional_lights: Query<
|
||||
(&Frustum, &mut VisibleEntities, Option<&RenderLayers>),
|
||||
With<DirectionalLight>,
|
||||
>,
|
||||
mut directional_lights: Query<(
|
||||
&DirectionalLight,
|
||||
&Frustum,
|
||||
&mut VisibleEntities,
|
||||
Option<&RenderLayers>,
|
||||
)>,
|
||||
mut visible_entity_query: Query<
|
||||
(
|
||||
Entity,
|
||||
|
@ -244,8 +264,16 @@ pub fn check_light_visibility(
|
|||
>,
|
||||
) {
|
||||
// Directonal lights
|
||||
for (frustum, mut visible_entities, maybe_view_mask) in directional_lights.iter_mut() {
|
||||
for (directional_light, frustum, mut visible_entities, maybe_view_mask) in
|
||||
directional_lights.iter_mut()
|
||||
{
|
||||
visible_entities.entities.clear();
|
||||
|
||||
// NOTE: If shadow mapping is disabled for the light then it must have no visible entities
|
||||
if !directional_light.shadows_enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
||||
|
||||
for (
|
||||
|
@ -288,6 +316,12 @@ pub fn check_light_visibility(
|
|||
for visible_entities in cubemap_visible_entities.iter_mut() {
|
||||
visible_entities.entities.clear();
|
||||
}
|
||||
|
||||
// NOTE: If shadow mapping is disabled for the light then it must have no visible entities
|
||||
if !point_light.shadows_enabled {
|
||||
continue;
|
||||
}
|
||||
|
||||
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
||||
let light_sphere = Sphere {
|
||||
center: transform.translation,
|
||||
|
|
|
@ -50,6 +50,7 @@ pub struct ExtractedPointLight {
|
|||
range: f32,
|
||||
radius: f32,
|
||||
transform: GlobalTransform,
|
||||
shadows_enabled: bool,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
@ -61,6 +62,7 @@ pub struct ExtractedDirectionalLight {
|
|||
illuminance: f32,
|
||||
direction: Vec3,
|
||||
projection: Mat4,
|
||||
shadows_enabled: bool,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
@ -77,20 +79,42 @@ pub struct GpuPointLight {
|
|||
radius: f32,
|
||||
near: f32,
|
||||
far: f32,
|
||||
flags: u32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
// NOTE: These must match the bit flags in bevy_pbr2/src/render/pbr.frag!
|
||||
bitflags::bitflags! {
|
||||
#[repr(transparent)]
|
||||
struct PointLightFlags: u32 {
|
||||
const SHADOWS_ENABLED = (1 << 0);
|
||||
const NONE = 0;
|
||||
const UNINITIALIZED = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, AsStd140, Default, Debug)]
|
||||
pub struct GpuDirectionalLight {
|
||||
view_projection: Mat4,
|
||||
color: Vec4,
|
||||
dir_to_light: Vec3,
|
||||
flags: u32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
// NOTE: These must match the bit flags in bevy_pbr2/src/render/pbr.frag!
|
||||
bitflags::bitflags! {
|
||||
#[repr(transparent)]
|
||||
struct DirectionalLightFlags: u32 {
|
||||
const SHADOWS_ENABLED = (1 << 0);
|
||||
const NONE = 0;
|
||||
const UNINITIALIZED = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, AsStd140)]
|
||||
pub struct GpuLights {
|
||||
|
@ -328,6 +352,7 @@ pub fn extract_lights(
|
|||
range: point_light.range,
|
||||
radius: point_light.radius,
|
||||
transform: *transform,
|
||||
shadows_enabled: point_light.shadows_enabled,
|
||||
shadow_depth_bias: point_light.shadow_depth_bias,
|
||||
// The factor of SQRT_2 is for the worst-case diagonal offset
|
||||
shadow_normal_bias: point_light.shadow_normal_bias
|
||||
|
@ -357,6 +382,7 @@ pub fn extract_lights(
|
|||
illuminance: directional_light.illuminance,
|
||||
direction: transform.forward(),
|
||||
projection: directional_light.shadow_projection.get_projection_matrix(),
|
||||
shadows_enabled: directional_light.shadows_enabled,
|
||||
shadow_depth_bias: directional_light.shadow_depth_bias,
|
||||
// The factor of SQRT_2 is for the worst-case diagonal offset
|
||||
shadow_normal_bias: directional_light.shadow_normal_bias
|
||||
|
@ -424,18 +450,24 @@ fn face_index_to_name(face_index: usize) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ViewLight {
|
||||
pub struct ShadowView {
|
||||
pub depth_texture_view: TextureView,
|
||||
pub pass_name: String,
|
||||
}
|
||||
|
||||
pub struct ViewLights {
|
||||
pub struct ViewShadowBindings {
|
||||
pub point_light_depth_texture: Texture,
|
||||
pub point_light_depth_texture_view: TextureView,
|
||||
pub directional_light_depth_texture: Texture,
|
||||
pub directional_light_depth_texture_view: TextureView,
|
||||
}
|
||||
|
||||
pub struct ViewLightEntities {
|
||||
pub lights: Vec<Entity>,
|
||||
pub gpu_light_binding_index: u32,
|
||||
}
|
||||
|
||||
pub struct ViewLightsUniformOffset {
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -524,54 +556,59 @@ pub fn prepare_lights(
|
|||
};
|
||||
|
||||
// TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query
|
||||
for (light_index, (light_entity, light)) in
|
||||
point_lights.iter().enumerate().take(MAX_POINT_LIGHTS)
|
||||
{
|
||||
for (light_index, (light_entity, light)) in point_lights.iter().enumerate() {
|
||||
// ignore scale because we don't want to effectively scale light radius and range
|
||||
// by applying those as a view transform to shadow map rendering of objects
|
||||
// and ignore rotation because we want the shadow map projections to align with the axes
|
||||
let view_translation = GlobalTransform::from_translation(light.transform.translation);
|
||||
|
||||
for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() {
|
||||
let depth_texture_view =
|
||||
point_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: Some("point_light_shadow_map_texture_view"),
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: (light_index * 6 + face_index) as u32,
|
||||
array_layer_count: NonZeroU32::new(1),
|
||||
});
|
||||
if light.shadows_enabled {
|
||||
for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() {
|
||||
let depth_texture_view =
|
||||
point_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: Some("point_light_shadow_map_texture_view"),
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: (light_index * 6 + face_index) as u32,
|
||||
array_layer_count: NonZeroU32::new(1),
|
||||
});
|
||||
|
||||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ViewLight {
|
||||
depth_texture_view,
|
||||
pass_name: format!(
|
||||
"shadow pass point light {} {}",
|
||||
light_index,
|
||||
face_index_to_name(face_index)
|
||||
),
|
||||
},
|
||||
ExtractedView {
|
||||
width: point_light_shadow_map.size as u32,
|
||||
height: point_light_shadow_map.size as u32,
|
||||
transform: view_translation * *view_rotation,
|
||||
projection: cube_face_projection,
|
||||
},
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Point {
|
||||
light_entity,
|
||||
face_index,
|
||||
},
|
||||
))
|
||||
.id();
|
||||
view_lights.push(view_light_entity);
|
||||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ShadowView {
|
||||
depth_texture_view,
|
||||
pass_name: format!(
|
||||
"shadow pass point light {} {}",
|
||||
light_index,
|
||||
face_index_to_name(face_index)
|
||||
),
|
||||
},
|
||||
ExtractedView {
|
||||
width: point_light_shadow_map.size as u32,
|
||||
height: point_light_shadow_map.size as u32,
|
||||
transform: view_translation * *view_rotation,
|
||||
projection: cube_face_projection,
|
||||
},
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Point {
|
||||
light_entity,
|
||||
face_index,
|
||||
},
|
||||
))
|
||||
.id();
|
||||
view_lights.push(view_light_entity);
|
||||
}
|
||||
}
|
||||
|
||||
let mut flags = PointLightFlags::NONE;
|
||||
if light.shadows_enabled {
|
||||
flags |= PointLightFlags::SHADOWS_ENABLED;
|
||||
}
|
||||
|
||||
gpu_lights.point_lights[light_index] = GpuPointLight {
|
||||
|
@ -584,6 +621,7 @@ pub fn prepare_lights(
|
|||
inverse_square_range: 1.0 / (light.range * light.range),
|
||||
near: 0.1,
|
||||
far: light.range,
|
||||
flags: flags.bits,
|
||||
shadow_depth_bias: light.shadow_depth_bias,
|
||||
shadow_normal_bias: light.shadow_normal_bias,
|
||||
};
|
||||
|
@ -616,6 +654,11 @@ pub fn prepare_lights(
|
|||
// NOTE: This orthographic projection defines the volume within which shadows from a directional light can be cast
|
||||
let projection = light.projection;
|
||||
|
||||
let mut flags = DirectionalLightFlags::NONE;
|
||||
if light.shadows_enabled {
|
||||
flags |= DirectionalLightFlags::SHADOWS_ENABLED;
|
||||
}
|
||||
|
||||
gpu_lights.directional_lights[i] = GpuDirectionalLight {
|
||||
// premultiply color by intensity
|
||||
// we don't use the alpha at all, so no reason to multiply only [0..3]
|
||||
|
@ -623,42 +666,45 @@ pub fn prepare_lights(
|
|||
dir_to_light,
|
||||
// NOTE: * view is correct, it should not be view.inverse() here
|
||||
view_projection: projection * view,
|
||||
flags: flags.bits,
|
||||
shadow_depth_bias: light.shadow_depth_bias,
|
||||
shadow_normal_bias: light.shadow_normal_bias,
|
||||
};
|
||||
|
||||
let depth_texture_view =
|
||||
directional_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: Some("directional_light_shadow_map_texture_view"),
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: i as u32,
|
||||
array_layer_count: NonZeroU32::new(1),
|
||||
});
|
||||
if light.shadows_enabled {
|
||||
let depth_texture_view =
|
||||
directional_light_depth_texture
|
||||
.texture
|
||||
.create_view(&TextureViewDescriptor {
|
||||
label: Some("directional_light_shadow_map_texture_view"),
|
||||
format: None,
|
||||
dimension: Some(TextureViewDimension::D2),
|
||||
aspect: TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: i as u32,
|
||||
array_layer_count: NonZeroU32::new(1),
|
||||
});
|
||||
|
||||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ViewLight {
|
||||
depth_texture_view,
|
||||
pass_name: format!("shadow pass directional light {}", i),
|
||||
},
|
||||
ExtractedView {
|
||||
width: directional_light_shadow_map.size as u32,
|
||||
height: directional_light_shadow_map.size as u32,
|
||||
transform: GlobalTransform::from_matrix(view.inverse()),
|
||||
projection,
|
||||
},
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Directional { light_entity },
|
||||
))
|
||||
.id();
|
||||
view_lights.push(view_light_entity);
|
||||
let view_light_entity = commands
|
||||
.spawn()
|
||||
.insert_bundle((
|
||||
ShadowView {
|
||||
depth_texture_view,
|
||||
pass_name: format!("shadow pass directional light {}", i),
|
||||
},
|
||||
ExtractedView {
|
||||
width: directional_light_shadow_map.size as u32,
|
||||
height: directional_light_shadow_map.size as u32,
|
||||
transform: GlobalTransform::from_matrix(view.inverse()),
|
||||
projection,
|
||||
},
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Directional { light_entity },
|
||||
))
|
||||
.id();
|
||||
view_lights.push(view_light_entity);
|
||||
}
|
||||
}
|
||||
let point_light_depth_texture_view =
|
||||
point_light_depth_texture
|
||||
|
@ -686,14 +732,20 @@ pub fn prepare_lights(
|
|||
array_layer_count: None,
|
||||
});
|
||||
|
||||
commands.entity(entity).insert(ViewLights {
|
||||
point_light_depth_texture: point_light_depth_texture.texture,
|
||||
point_light_depth_texture_view,
|
||||
directional_light_depth_texture: directional_light_depth_texture.texture,
|
||||
directional_light_depth_texture_view,
|
||||
lights: view_lights,
|
||||
gpu_light_binding_index: light_meta.view_gpu_lights.push(gpu_lights),
|
||||
});
|
||||
commands.entity(entity).insert_bundle((
|
||||
ViewShadowBindings {
|
||||
point_light_depth_texture: point_light_depth_texture.texture,
|
||||
point_light_depth_texture_view,
|
||||
directional_light_depth_texture: directional_light_depth_texture.texture,
|
||||
directional_light_depth_texture_view,
|
||||
},
|
||||
ViewLightEntities {
|
||||
lights: view_lights,
|
||||
},
|
||||
ViewLightsUniformOffset {
|
||||
offset: light_meta.view_gpu_lights.push(gpu_lights),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
light_meta
|
||||
|
@ -728,12 +780,12 @@ pub fn queue_shadows(
|
|||
render_meshes: Res<RenderAssets<Mesh>>,
|
||||
mut pipelines: ResMut<SpecializedPipelines<ShadowPipeline>>,
|
||||
mut pipeline_cache: ResMut<RenderPipelineCache>,
|
||||
mut view_lights: Query<&ViewLights>,
|
||||
view_lights: Query<&ViewLightEntities>,
|
||||
mut view_light_shadow_phases: Query<(&LightEntity, &mut RenderPhase<Shadow>)>,
|
||||
point_light_entities: Query<&CubemapVisibleEntities, With<ExtractedPointLight>>,
|
||||
directional_light_entities: Query<&VisibleEntities, With<ExtractedDirectionalLight>>,
|
||||
) {
|
||||
for view_lights in view_lights.iter_mut() {
|
||||
for view_lights in view_lights.iter() {
|
||||
let draw_shadow_mesh = shadow_draw_functions
|
||||
.read()
|
||||
.get_id::<DrawShadowMesh>()
|
||||
|
@ -753,6 +805,8 @@ pub fn queue_shadows(
|
|||
.expect("Failed to get point light visible entities")
|
||||
.get(*face_index),
|
||||
};
|
||||
// NOTE: Lights with shadow mapping disabled will have no visible entities
|
||||
// so no meshes will be queued
|
||||
for VisibleEntity { entity, .. } in visible_entities.iter() {
|
||||
let mut key = ShadowPipelineKey::empty();
|
||||
if let Ok(mesh_handle) = casting_meshes.get(*entity) {
|
||||
|
@ -811,8 +865,8 @@ impl CachedPipelinePhaseItem for Shadow {
|
|||
}
|
||||
|
||||
pub struct ShadowPassNode {
|
||||
main_view_query: QueryState<&'static ViewLights>,
|
||||
view_light_query: QueryState<(&'static ViewLight, &'static RenderPhase<Shadow>)>,
|
||||
main_view_query: QueryState<&'static ViewLightEntities>,
|
||||
view_light_query: QueryState<(&'static ShadowView, &'static RenderPhase<Shadow>)>,
|
||||
}
|
||||
|
||||
impl ShadowPassNode {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::{LightMeta, NotShadowCaster, NotShadowReceiver, ShadowPipeline, ViewLights};
|
||||
use crate::{
|
||||
LightMeta, NotShadowCaster, NotShadowReceiver, ShadowPipeline, ViewLightsUniformOffset,
|
||||
ViewShadowBindings,
|
||||
};
|
||||
use bevy_app::Plugin;
|
||||
use bevy_asset::{Assets, Handle, HandleUntyped};
|
||||
use bevy_ecs::{
|
||||
|
@ -523,13 +526,13 @@ pub fn queue_mesh_view_bind_groups(
|
|||
shadow_pipeline: Res<ShadowPipeline>,
|
||||
light_meta: Res<LightMeta>,
|
||||
view_uniforms: Res<ViewUniforms>,
|
||||
mut views: Query<(Entity, &ViewLights)>,
|
||||
mut views: Query<(Entity, &ViewShadowBindings)>,
|
||||
) {
|
||||
if let (Some(view_binding), Some(light_binding)) = (
|
||||
view_uniforms.uniforms.binding(),
|
||||
light_meta.view_gpu_lights.binding(),
|
||||
) {
|
||||
for (entity, view_lights) in views.iter_mut() {
|
||||
for (entity, view_shadow_bindings) in views.iter_mut() {
|
||||
let view_bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
||||
entries: &[
|
||||
BindGroupEntry {
|
||||
|
@ -543,7 +546,7 @@ pub fn queue_mesh_view_bind_groups(
|
|||
BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: BindingResource::TextureView(
|
||||
&view_lights.point_light_depth_texture_view,
|
||||
&view_shadow_bindings.point_light_depth_texture_view,
|
||||
),
|
||||
},
|
||||
BindGroupEntry {
|
||||
|
@ -553,7 +556,7 @@ pub fn queue_mesh_view_bind_groups(
|
|||
BindGroupEntry {
|
||||
binding: 4,
|
||||
resource: BindingResource::TextureView(
|
||||
&view_lights.directional_light_depth_texture_view,
|
||||
&view_shadow_bindings.directional_light_depth_texture_view,
|
||||
),
|
||||
},
|
||||
BindGroupEntry {
|
||||
|
@ -578,7 +581,7 @@ pub struct SetMeshViewBindGroup<const I: usize>;
|
|||
impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
|
||||
type Param = SQuery<(
|
||||
Read<ViewUniformOffset>,
|
||||
Read<ViewLights>,
|
||||
Read<ViewLightsUniformOffset>,
|
||||
Read<MeshViewBindGroup>,
|
||||
)>;
|
||||
#[inline]
|
||||
|
@ -592,7 +595,7 @@ impl<const I: usize> EntityRenderCommand for SetMeshViewBindGroup<I> {
|
|||
pass.set_bind_group(
|
||||
I,
|
||||
&mesh_view_bind_group.value,
|
||||
&[view_uniform.offset, view_lights.gpu_light_binding_index],
|
||||
&[view_uniform.offset, view_lights.offset],
|
||||
);
|
||||
|
||||
RenderCommandResult::Success
|
||||
|
|
|
@ -13,18 +13,26 @@ struct PointLight {
|
|||
radius: f32;
|
||||
near: f32;
|
||||
far: f32;
|
||||
// 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options.
|
||||
flags: u32;
|
||||
shadow_depth_bias: f32;
|
||||
shadow_normal_bias: f32;
|
||||
};
|
||||
|
||||
let POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT: u32 = 1u;
|
||||
|
||||
struct DirectionalLight {
|
||||
view_projection: mat4x4<f32>;
|
||||
color: vec4<f32>;
|
||||
direction_to_light: vec3<f32>;
|
||||
// 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options.
|
||||
flags: u32;
|
||||
shadow_depth_bias: f32;
|
||||
shadow_normal_bias: f32;
|
||||
};
|
||||
|
||||
let DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT: u32 = 1u;
|
||||
|
||||
[[block]]
|
||||
struct Lights {
|
||||
// NOTE: this array size must be kept in sync with the constants defined bevy_pbr2/src/render/light.rs
|
||||
|
@ -47,4 +55,4 @@ var point_shadow_textures_sampler: sampler_comparison;
|
|||
[[group(0), binding(4)]]
|
||||
var directional_shadow_textures: texture_depth_2d_array;
|
||||
[[group(0), binding(5)]]
|
||||
var directional_shadow_textures_sampler: sampler_comparison;
|
||||
var directional_shadow_textures_sampler: sampler_comparison;
|
||||
|
|
|
@ -500,7 +500,8 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
|||
for (var i: i32 = 0; i < n_point_lights; i = i + 1) {
|
||||
let light = lights.point_lights[i];
|
||||
var shadow: f32;
|
||||
if ((mesh.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u) {
|
||||
if ((mesh.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u
|
||||
|| (light.flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
|
||||
shadow = fetch_point_shadow(i, in.world_position, in.world_normal);
|
||||
} else {
|
||||
shadow = 1.0;
|
||||
|
@ -511,7 +512,8 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
|||
for (var i: i32 = 0; i < n_directional_lights; i = i + 1) {
|
||||
let light = lights.directional_lights[i];
|
||||
var shadow: f32;
|
||||
if ((mesh.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u) {
|
||||
if ((mesh.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u
|
||||
|| (light.flags & DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
|
||||
shadow = fetch_directional_shadow(i, in.world_position, in.world_normal);
|
||||
} else {
|
||||
shadow = 1.0;
|
||||
|
|
Loading…
Reference in a new issue