Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
176b3ee
Add flag to Camera for its own shadow maps
kfc35 Jun 11, 2026
df77727
wip: additional point and spot light shadow maps per opt-in view
kfc35 Jun 12, 2026
d3bd801
point lights are fixed! testbed 3d render layers looks good
kfc35 Jun 13, 2026
0c40e77
refactor: create_point_shadow_maps function extracted
kfc35 Jun 13, 2026
9d48c13
finish impl for point light shadow maps
kfc35 Jun 14, 2026
975df5a
simplify some logic
kfc35 Jun 14, 2026
8c5a50b
refactor: separate out create spot light shadow map into fn
kfc35 Jun 14, 2026
219bf58
include spot shadow views in gpu preprocess
kfc35 Jun 14, 2026
0acefb4
add spot light to shadow pass code
kfc35 Jun 14, 2026
335a132
finish impl for prepare spot light shadow maps
kfc35 Jun 14, 2026
d01ff65
use correct index for spot shadows
kfc35 Jun 14, 2026
63fc417
refactor: light_index -> array_index
kfc35 Jun 14, 2026
979ede1
more words for has_own_shadow_maps doc comment
kfc35 Jun 14, 2026
e877e17
Fix 3d render layers testbed
kfc35 Jun 14, 2026
c6ea45d
remove println statements
kfc35 Jun 14, 2026
34ccba8
clean up additional shadow maps if light does not have them enabled
kfc35 Jun 14, 2026
692cf82
add comment on potentially confusing code in prepare_view_uniforms
kfc35 Jun 14, 2026
57c7b8d
fmt
kfc35 Jun 14, 2026
89ced9c
lint
kfc35 Jun 14, 2026
6c2da6b
clippy
kfc35 Jun 14, 2026
e9f8e87
fix volumetric fog
kfc35 Jun 14, 2026
c84d702
wip: fix wgsl indexing of point and spot shadow maps
kfc35 Jun 14, 2026
40c1ba5
fix removal bug in light.rs
kfc35 Jun 14, 2026
ad3d74b
ensure limits to shadow maps are respected
kfc35 Jun 15, 2026
57090ff
clippy
kfc35 Jun 15, 2026
793914f
readjust depth_or_array_layers
kfc35 Jun 15, 2026
cf1ab11
fix usage of depth attachment hash maps
kfc35 Jun 15, 2026
9135a89
Merge branch 'main' of github.com:kfc35/bevy into 23978_per_camera_sh…
kfc35 Jun 17, 2026
881db76
fix clippy
kfc35 Jun 17, 2026
9703056
remove unnecessary newline
kfc35 Jun 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions crates/bevy_camera/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,17 @@ pub struct Camera {
pub invert_culling: bool,
/// If set, this camera will be a sub camera of a large view, defined by a [`SubCameraView`].
pub sub_camera_view: Option<SubCameraView>,
/// Whether this camera will generate its own shadow maps for any lights in the scene.
///
/// If true, shadow maps unique to this camera will be generated.
/// The shadow maps will be generated using the same render layers and HLOD configuration as this camera.
/// The light's render layers **must** be a superset of this camera's render layers in order for this to work properly.
///
/// Enabling this setting can have a negative impact on performance. Point lights in particular
/// will generate 6 additional shadow maps per camera that opts to have its own shadow maps.
///
/// Defaults to `false`.
pub has_own_shadow_maps: bool,
}

impl Default for Camera {
Expand All @@ -424,6 +435,7 @@ impl Default for Camera {
clear_color: Default::default(),
invert_culling: false,
sub_camera_view: None,
has_own_shadow_maps: false,
}
}
}
Expand Down
69 changes: 60 additions & 9 deletions crates/bevy_pbr/src/render/gpu_preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ use bitflags::bitflags;
use smallvec::{smallvec, SmallVec};
use tracing::warn;

use crate::{LightEntity, MeshCullingData, MeshCullingDataBuffer, MeshInputUniform, MeshUniform};
use crate::{
LightEntity, MeshCullingData, MeshCullingDataBuffer, MeshInputUniform, MeshUniform,
PointLightShadowViewEntities, SpotLightShadowViewEntity,
};

use super::{ShadowView, ViewLightEntities};

Expand Down Expand Up @@ -524,7 +527,14 @@ pub fn clear_indirect_parameters_metadata(
/// to frame, we avoid having to perform a CPU-side traversal of every mesh
/// instance every frame.
pub fn unpack_bins(
current_view: ViewQuery<Option<&ViewLightEntities>, Without<SkipGpuPreprocess>>,
current_view: ViewQuery<
(
Option<&ViewLightEntities>,
Option<&PointLightShadowViewEntities>,
Option<&SpotLightShadowViewEntity>,
),
Without<SkipGpuPreprocess>,
>,
view_query: Query<&ExtractedView, Without<SkipGpuPreprocess>>,
light_query: Query<&LightEntity>,
batched_instance_buffers: Res<BatchedInstanceBuffers<MeshUniform, MeshInputUniform>>,
Expand All @@ -546,9 +556,15 @@ pub fn unpack_bins(

// Gather up all views.
let view_entity = current_view.entity();
let shadow_cascade_views = current_view.into_inner();
let all_views =
gather_shadow_cascades_for_view(view_entity, shadow_cascade_views, &light_query);
let (shadow_cascade_views, point_light_shadow_views, spot_light_shadow_view) =
current_view.into_inner();
let all_views = gather_shadow_cascades_for_view(
view_entity,
shadow_cascade_views,
point_light_shadow_views,
spot_light_shadow_view,
&light_query,
);

// Don't run if the shaders haven't been compiled yet.
if let Some(bin_unpacking_pipeline_id) = preprocess_pipelines.bin_unpacking.pipeline_id
Expand Down Expand Up @@ -600,7 +616,14 @@ pub fn unpack_bins(
}

pub fn early_gpu_preprocess(
current_view: ViewQuery<Option<&ViewLightEntities>, Without<SkipGpuPreprocess>>,
current_view: ViewQuery<
(
Option<&ViewLightEntities>,
Option<&PointLightShadowViewEntities>,
Option<&SpotLightShadowViewEntity>,
),
Without<SkipGpuPreprocess>,
>,
view_query: Query<
(
&ExtractedView,
Expand Down Expand Up @@ -630,9 +653,15 @@ pub fn early_gpu_preprocess(
let pass_span = diagnostics.pass_span(&mut compute_pass, "early_mesh_preprocessing");

let view_entity = current_view.entity();
let shadow_cascade_views = current_view.into_inner();
let all_views =
gather_shadow_cascades_for_view(view_entity, shadow_cascade_views, &light_query);
let (shadow_cascade_views, point_light_shadow_views, spot_light_shadow_view) =
current_view.into_inner();
let all_views = gather_shadow_cascades_for_view(
view_entity,
shadow_cascade_views,
point_light_shadow_views,
spot_light_shadow_view,
&light_query,
);

// Run the compute passes.
for view_entity in all_views {
Expand Down Expand Up @@ -795,6 +824,8 @@ pub fn early_gpu_preprocess(
fn gather_shadow_cascades_for_view(
view_entity: Entity,
shadow_cascade_views: Option<&ViewLightEntities>,
point_light_shadow_views: Option<&PointLightShadowViewEntities>,
spot_light_shadow_view: Option<&SpotLightShadowViewEntity>,
light_query: &Query<&LightEntity>,
) -> SmallVec<[Entity; 8]> {
let mut all_views: SmallVec<[_; 8]> = SmallVec::new();
Expand All @@ -812,6 +843,26 @@ fn gather_shadow_cascades_for_view(
.copied(),
);
}
if let Some(point_light_shadow_views) = point_light_shadow_views {
all_views.extend(
point_light_shadow_views
.shadow_view_entities
.iter()
.filter(|light_entity| {
light_query.get(**light_entity).is_ok_and(|light_entity| {
matches!(*light_entity, LightEntity::Point { .. })
})
})
.copied(),
);
}
if let Some(spot_light_shadow_view) = spot_light_shadow_view
&& light_query
.get(spot_light_shadow_view.shadow_view_entity)
.is_ok_and(|light_entity| matches!(*light_entity, LightEntity::Spot { .. }))
{
all_views.push(spot_light_shadow_view.shadow_view_entity);
}
all_views
}

Expand Down
Loading