@@ -5,6 +5,7 @@ use bevy_render::{
5
5
camera:: Camera ,
6
6
color:: Color ,
7
7
mesh:: Mesh ,
8
+ primitives:: { CascadesFrusta , CubemapFrusta , Frustum } ,
8
9
render_asset:: RenderAssets ,
9
10
render_graph:: { Node , NodeRunError , RenderGraphContext } ,
10
11
render_phase:: * ,
@@ -48,6 +49,7 @@ pub struct ExtractedDirectionalLight {
48
49
shadow_normal_bias : f32 ,
49
50
cascade_shadow_config : CascadeShadowConfig ,
50
51
cascades : EntityHashMap < Entity , Vec < Cascade > > ,
52
+ frusta : EntityHashMap < Entity , Vec < Frustum > > ,
51
53
render_layers : RenderLayers ,
52
54
}
53
55
@@ -296,6 +298,7 @@ pub fn extract_lights(
296
298
& CubemapVisibleEntities ,
297
299
& GlobalTransform ,
298
300
& ViewVisibility ,
301
+ & CubemapFrusta ,
299
302
) > ,
300
303
> ,
301
304
spot_lights : Extract <
@@ -304,6 +307,7 @@ pub fn extract_lights(
304
307
& VisibleEntities ,
305
308
& GlobalTransform ,
306
309
& ViewVisibility ,
310
+ & Frustum ,
307
311
) > ,
308
312
> ,
309
313
directional_lights : Extract <
@@ -314,6 +318,7 @@ pub fn extract_lights(
314
318
& CascadesVisibleEntities ,
315
319
& Cascades ,
316
320
& CascadeShadowConfig ,
321
+ & CascadesFrusta ,
317
322
& GlobalTransform ,
318
323
& ViewVisibility ,
319
324
Option < & RenderLayers > ,
@@ -343,7 +348,7 @@ pub fn extract_lights(
343
348
344
349
let mut point_lights_values = Vec :: with_capacity ( * previous_point_lights_len) ;
345
350
for entity in global_point_lights. iter ( ) . copied ( ) {
346
- let Ok ( ( point_light, cubemap_visible_entities, transform, view_visibility) ) =
351
+ let Ok ( ( point_light, cubemap_visible_entities, transform, view_visibility, frusta ) ) =
347
352
point_lights. get ( entity)
348
353
else {
349
354
continue ;
@@ -373,15 +378,19 @@ pub fn extract_lights(
373
378
} ;
374
379
point_lights_values. push ( (
375
380
entity,
376
- ( extracted_point_light, render_cubemap_visible_entities) ,
381
+ (
382
+ extracted_point_light,
383
+ render_cubemap_visible_entities,
384
+ ( * frusta) . clone ( ) ,
385
+ ) ,
377
386
) ) ;
378
387
}
379
388
* previous_point_lights_len = point_lights_values. len ( ) ;
380
389
commands. insert_or_spawn_batch ( point_lights_values) ;
381
390
382
391
let mut spot_lights_values = Vec :: with_capacity ( * previous_spot_lights_len) ;
383
392
for entity in global_point_lights. iter ( ) . copied ( ) {
384
- if let Ok ( ( spot_light, visible_entities, transform, view_visibility) ) =
393
+ if let Ok ( ( spot_light, visible_entities, transform, view_visibility, frustum ) ) =
385
394
spot_lights. get ( entity)
386
395
{
387
396
if !view_visibility. get ( ) {
@@ -417,6 +426,7 @@ pub fn extract_lights(
417
426
spot_light_angles : Some ( ( spot_light. inner_angle , spot_light. outer_angle ) ) ,
418
427
} ,
419
428
render_visible_entities,
429
+ * frustum,
420
430
) ,
421
431
) ) ;
422
432
}
@@ -430,6 +440,7 @@ pub fn extract_lights(
430
440
visible_entities,
431
441
cascades,
432
442
cascade_config,
443
+ frusta,
433
444
transform,
434
445
view_visibility,
435
446
maybe_layers,
@@ -452,6 +463,7 @@ pub fn extract_lights(
452
463
shadow_normal_bias : directional_light. shadow_normal_bias * std:: f32:: consts:: SQRT_2 ,
453
464
cascade_shadow_config : cascade_config. clone ( ) ,
454
465
cascades : cascades. cascades . clone ( ) ,
466
+ frusta : frusta. frusta . clone ( ) ,
455
467
render_layers : maybe_layers. copied ( ) . unwrap_or_default ( ) ,
456
468
} ,
457
469
render_visible_entities,
@@ -656,7 +668,11 @@ pub fn prepare_lights(
656
668
directional_light_shadow_map : Res < DirectionalLightShadowMap > ,
657
669
mut max_directional_lights_warning_emitted : Local < bool > ,
658
670
mut max_cascades_per_light_warning_emitted : Local < bool > ,
659
- point_lights : Query < ( Entity , & ExtractedPointLight ) > ,
671
+ point_lights : Query < (
672
+ Entity ,
673
+ & ExtractedPointLight ,
674
+ AnyOf < ( & CubemapFrusta , & Frustum ) > ,
675
+ ) > ,
660
676
directional_lights : Query < ( Entity , & ExtractedDirectionalLight ) > ,
661
677
) {
662
678
let views_iter = views. iter ( ) ;
@@ -733,7 +749,7 @@ pub fn prepare_lights(
733
749
734
750
let spot_light_shadow_maps_count = point_lights
735
751
. iter ( )
736
- . filter ( |( _, light) | light. shadows_enabled && light. spot_light_angles . is_some ( ) )
752
+ . filter ( |( _, light, _ ) | light. shadows_enabled && light. spot_light_angles . is_some ( ) )
737
753
. count ( )
738
754
. min ( max_texture_array_layers - directional_shadow_enabled_count * MAX_CASCADES_PER_LIGHT ) ;
739
755
@@ -742,7 +758,7 @@ pub fn prepare_lights(
742
758
// - then those with shadows enabled first, so that the index can be used to render at most `point_light_shadow_maps_count`
743
759
// point light shadows and `spot_light_shadow_maps_count` spot light shadow maps,
744
760
// - then by entity as a stable key to ensure that a consistent set of lights are chosen if the light count limit is exceeded.
745
- point_lights. sort_by ( |( entity_1, light_1) , ( entity_2, light_2) | {
761
+ point_lights. sort_by ( |( entity_1, light_1, _ ) , ( entity_2, light_2, _ ) | {
746
762
point_light_order (
747
763
(
748
764
entity_1,
@@ -775,7 +791,7 @@ pub fn prepare_lights(
775
791
}
776
792
777
793
let mut gpu_point_lights = Vec :: new ( ) ;
778
- for ( index, & ( entity, light) ) in point_lights. iter ( ) . enumerate ( ) {
794
+ for ( index, & ( entity, light, _ ) ) in point_lights. iter ( ) . enumerate ( ) {
779
795
let mut flags = PointLightFlags :: NONE ;
780
796
781
797
// Lights are sorted, shadow enabled lights are first
@@ -952,11 +968,11 @@ pub fn prepare_lights(
952
968
} ;
953
969
954
970
// TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query
955
- for & ( light_entity, light) in point_lights
971
+ for & ( light_entity, light, ( point_light_frusta , _ ) ) in point_lights
956
972
. iter ( )
957
973
// Lights are sorted, shadow enabled lights are first
958
974
. take ( point_light_shadow_maps_count)
959
- . filter ( |( _, light) | light. shadows_enabled )
975
+ . filter ( |( _, light, _ ) | light. shadows_enabled )
960
976
{
961
977
let light_index = * global_light_meta
962
978
. entity_to_index
@@ -967,7 +983,11 @@ pub fn prepare_lights(
967
983
// and ignore rotation because we want the shadow map projections to align with the axes
968
984
let view_translation = GlobalTransform :: from_translation ( light. transform . translation ( ) ) ;
969
985
970
- for ( face_index, view_rotation) in cube_face_rotations. iter ( ) . enumerate ( ) {
986
+ for ( face_index, ( view_rotation, frustum) ) in cube_face_rotations
987
+ . iter ( )
988
+ . zip ( & point_light_frusta. unwrap ( ) . frusta )
989
+ . enumerate ( )
990
+ {
971
991
let depth_texture_view =
972
992
point_light_depth_texture
973
993
. texture
@@ -1005,6 +1025,7 @@ pub fn prepare_lights(
1005
1025
hdr : false ,
1006
1026
color_grading : Default :: default ( ) ,
1007
1027
} ,
1028
+ * frustum,
1008
1029
RenderPhase :: < Shadow > :: default ( ) ,
1009
1030
LightEntity :: Point {
1010
1031
light_entity,
@@ -1017,7 +1038,7 @@ pub fn prepare_lights(
1017
1038
}
1018
1039
1019
1040
// spot lights
1020
- for ( light_index, & ( light_entity, light) ) in point_lights
1041
+ for ( light_index, & ( light_entity, light, ( _ , spot_light_frustum ) ) ) in point_lights
1021
1042
. iter ( )
1022
1043
. skip ( point_light_count)
1023
1044
. take ( spot_light_shadow_maps_count)
@@ -1063,6 +1084,7 @@ pub fn prepare_lights(
1063
1084
hdr : false ,
1064
1085
color_grading : Default :: default ( ) ,
1065
1086
} ,
1087
+ * spot_light_frustum. unwrap ( ) ,
1066
1088
RenderPhase :: < Shadow > :: default ( ) ,
1067
1089
LightEntity :: Spot { light_entity } ,
1068
1090
) )
@@ -1078,12 +1100,20 @@ pub fn prepare_lights(
1078
1100
. enumerate ( )
1079
1101
. take ( directional_shadow_enabled_count)
1080
1102
{
1081
- for ( cascade_index , ( cascade , bound ) ) in light
1103
+ let cascades = light
1082
1104
. cascades
1083
1105
. get ( & entity)
1084
1106
. unwrap ( )
1085
1107
. iter ( )
1086
- . take ( MAX_CASCADES_PER_LIGHT )
1108
+ . take ( MAX_CASCADES_PER_LIGHT ) ;
1109
+ let frusta = light
1110
+ . frusta
1111
+ . get ( & entity)
1112
+ . unwrap ( )
1113
+ . iter ( )
1114
+ . take ( MAX_CASCADES_PER_LIGHT ) ;
1115
+ for ( cascade_index, ( ( cascade, frusta) , bound) ) in cascades
1116
+ . zip ( frusta)
1087
1117
. zip ( & light. cascade_shadow_config . bounds )
1088
1118
. enumerate ( )
1089
1119
{
@@ -1129,6 +1159,7 @@ pub fn prepare_lights(
1129
1159
hdr : false ,
1130
1160
color_grading : Default :: default ( ) ,
1131
1161
} ,
1162
+ * frusta,
1132
1163
RenderPhase :: < Shadow > :: default ( ) ,
1133
1164
LightEntity :: Directional {
1134
1165
light_entity,
0 commit comments