1
1
use crate :: {
2
2
environment_map, prepass, EnvironmentMapLight , FogMeta , GlobalLightMeta , GpuFog , GpuLights ,
3
3
GpuPointLights , LightMeta , NotShadowCaster , NotShadowReceiver , PreviousGlobalTransform ,
4
- ShadowSamplers , ViewClusterBindings , ViewFogUniformOffset , ViewLightsUniformOffset ,
5
- ViewShadowBindings , CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT , MAX_CASCADES_PER_LIGHT ,
6
- MAX_DIRECTIONAL_LIGHTS ,
4
+ ScreenSpaceAmbientOcclusionTextures , ShadowSamplers , ViewClusterBindings , ViewFogUniformOffset ,
5
+ ViewLightsUniformOffset , ViewShadowBindings , CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT ,
6
+ MAX_CASCADES_PER_LIGHT , MAX_DIRECTIONAL_LIGHTS ,
7
7
} ;
8
8
use bevy_app:: Plugin ;
9
9
use bevy_asset:: { load_internal_asset, Assets , Handle , HandleUntyped } ;
@@ -433,22 +433,33 @@ impl FromWorld for MeshPipeline {
433
433
} ,
434
434
count: None ,
435
435
} ,
436
+ // Screen space ambient occlusion texture
437
+ BindGroupLayoutEntry {
438
+ binding: 11 ,
439
+ visibility: ShaderStages :: FRAGMENT ,
440
+ ty: BindingType :: Texture {
441
+ multisampled: false ,
442
+ sample_type: TextureSampleType :: Float { filterable: false } ,
443
+ view_dimension: TextureViewDimension :: D2 ,
444
+ } ,
445
+ count: None ,
446
+ } ,
436
447
] ;
437
448
438
449
// EnvironmentMapLight
439
450
let environment_map_entries =
440
- environment_map:: get_bind_group_layout_entries ( [ 11 , 12 , 13 ] ) ;
451
+ environment_map:: get_bind_group_layout_entries ( [ 12 , 13 , 14 ] ) ;
441
452
entries. extend_from_slice ( & environment_map_entries) ;
442
453
443
454
// Tonemapping
444
- let tonemapping_lut_entries = get_lut_bind_group_layout_entries ( [ 14 , 15 ] ) ;
455
+ let tonemapping_lut_entries = get_lut_bind_group_layout_entries ( [ 15 , 16 ] ) ;
445
456
entries. extend_from_slice ( & tonemapping_lut_entries) ;
446
457
447
458
if cfg ! ( any( not( feature = "webgl" ) , not( target_arch = "wasm32" ) ) )
448
459
|| ( cfg ! ( all( feature = "webgl" , target_arch = "wasm32" ) ) && !multisampled)
449
460
{
450
461
entries. extend_from_slice ( & prepass:: get_bind_group_layout_entries (
451
- [ 16 , 17 , 18 ] ,
462
+ [ 17 , 18 , 19 ] ,
452
463
multisampled,
453
464
) ) ;
454
465
}
@@ -586,8 +597,9 @@ bitflags::bitflags! {
586
597
const MAY_DISCARD = ( 1 << 6 ) ; // Guards shader codepaths that may discard, allowing early depth tests in most cases
587
598
// See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test
588
599
const ENVIRONMENT_MAP = ( 1 << 7 ) ;
589
- const DEPTH_CLAMP_ORTHO = ( 1 << 8 ) ;
590
- const TAA = ( 1 << 9 ) ;
600
+ const SCREEN_SPACE_AMBIENT_OCCLUSION = ( 1 << 8 ) ;
601
+ const DEPTH_CLAMP_ORTHO = ( 1 << 9 ) ;
602
+ const TAA = ( 1 << 10 ) ;
591
603
const BLEND_RESERVED_BITS = Self :: BLEND_MASK_BITS << Self :: BLEND_SHIFT_BITS ; // ← Bitmask reserving bits for the blend state
592
604
const BLEND_OPAQUE = ( 0 << Self :: BLEND_SHIFT_BITS ) ; // ← Values are just sequential within the mask, and can range from 0 to 3
593
605
const BLEND_PREMULTIPLIED_ALPHA = ( 1 << Self :: BLEND_SHIFT_BITS ) ; //
@@ -727,6 +739,10 @@ impl SpecializedMeshPipeline for MeshPipeline {
727
739
bind_group_layout. push ( self . mesh_layout . clone ( ) ) ;
728
740
} ;
729
741
742
+ if key. contains ( MeshPipelineKey :: SCREEN_SPACE_AMBIENT_OCCLUSION ) {
743
+ shader_defs. push ( "SCREEN_SPACE_AMBIENT_OCCLUSION" . into ( ) ) ;
744
+ }
745
+
730
746
let vertex_buffer_layout = layout. get_layout ( & vertex_attributes) ?;
731
747
732
748
let ( label, blend, depth_write_enabled) ;
@@ -974,6 +990,7 @@ pub fn queue_mesh_view_bind_groups(
974
990
Entity ,
975
991
& ViewShadowBindings ,
976
992
& ViewClusterBindings ,
993
+ Option < & ScreenSpaceAmbientOcclusionTextures > ,
977
994
Option < & ViewPrepassTextures > ,
978
995
Option < & EnvironmentMapLight > ,
979
996
& Tonemapping ,
@@ -1003,11 +1020,17 @@ pub fn queue_mesh_view_bind_groups(
1003
1020
entity,
1004
1021
view_shadow_bindings,
1005
1022
view_cluster_bindings,
1023
+ ssao_textures,
1006
1024
prepass_textures,
1007
1025
environment_map,
1008
1026
tonemapping,
1009
1027
) in & views
1010
1028
{
1029
+ let fallback_ssao = fallback_images
1030
+ . image_for_samplecount ( 1 )
1031
+ . texture_view
1032
+ . clone ( ) ;
1033
+
1011
1034
let layout = if msaa. samples ( ) > 1 {
1012
1035
& mesh_pipeline. view_layout_multisampled
1013
1036
} else {
@@ -1063,18 +1086,26 @@ pub fn queue_mesh_view_bind_groups(
1063
1086
binding: 10 ,
1064
1087
resource: fog_binding. clone( ) ,
1065
1088
} ,
1089
+ BindGroupEntry {
1090
+ binding: 11 ,
1091
+ resource: BindingResource :: TextureView (
1092
+ ssao_textures
1093
+ . map( |t| & t. screen_space_ambient_occlusion_texture. default_view)
1094
+ . unwrap_or( & fallback_ssao) ,
1095
+ ) ,
1096
+ } ,
1066
1097
] ;
1067
1098
1068
1099
let env_map = environment_map:: get_bindings (
1069
1100
environment_map,
1070
1101
& images,
1071
1102
& fallback_cubemap,
1072
- [ 11 , 12 , 13 ] ,
1103
+ [ 12 , 13 , 14 ] ,
1073
1104
) ;
1074
1105
entries. extend_from_slice ( & env_map) ;
1075
1106
1076
1107
let tonemapping_luts =
1077
- get_lut_bindings ( & images, & tonemapping_luts, tonemapping, [ 14 , 15 ] ) ;
1108
+ get_lut_bindings ( & images, & tonemapping_luts, tonemapping, [ 15 , 16 ] ) ;
1078
1109
entries. extend_from_slice ( & tonemapping_luts) ;
1079
1110
1080
1111
// When using WebGL, we can't have a depth texture with multisampling
@@ -1086,7 +1117,7 @@ pub fn queue_mesh_view_bind_groups(
1086
1117
& mut fallback_images,
1087
1118
& mut fallback_depths,
1088
1119
& msaa,
1089
- [ 16 , 17 , 18 ] ,
1120
+ [ 17 , 18 , 19 ] ,
1090
1121
) ) ;
1091
1122
}
1092
1123
0 commit comments