11//! Screen space reflections implemented via raymarching.
22
33use bevy_app:: { App , Plugin } ;
4- use bevy_asset:: { load_embedded_asset, Handle } ;
4+ use bevy_asset:: { load_embedded_asset, AssetServer , Handle } ;
55use bevy_core_pipeline:: {
66 core_3d:: {
77 graph:: { Core3d , Node3d } ,
@@ -19,7 +19,7 @@ use bevy_ecs::{
1919 resource:: Resource ,
2020 schedule:: IntoScheduleConfigs as _,
2121 system:: { lifetimeless:: Read , Commands , Query , Res , ResMut } ,
22- world:: { FromWorld , World } ,
22+ world:: World ,
2323} ;
2424use bevy_image:: BevyDefault as _;
2525use bevy_reflect:: { std_traits:: ReflectDefault , Reflect } ;
@@ -36,7 +36,7 @@ use bevy_render::{
3636 } ,
3737 renderer:: { RenderAdapter , RenderContext , RenderDevice , RenderQueue } ,
3838 view:: { ExtractedView , Msaa , ViewTarget , ViewUniformOffset } ,
39- Render , RenderApp , RenderSystems ,
39+ Render , RenderApp , RenderStartup , RenderSystems ,
4040} ;
4141use bevy_render:: { load_shader_library, render_graph:: RenderGraph } ;
4242use bevy_utils:: { once, prelude:: default} ;
@@ -190,50 +190,41 @@ impl Plugin for ScreenSpaceReflectionsPlugin {
190190
191191 render_app
192192 . init_resource :: < ScreenSpaceReflectionsBuffer > ( )
193+ . init_resource :: < SpecializedRenderPipelines < ScreenSpaceReflectionsPipeline > > ( )
194+ . add_systems (
195+ RenderStartup ,
196+ (
197+ init_screen_space_reflections_pipeline,
198+ add_screen_space_reflections_render_graph_edges,
199+ ) ,
200+ )
193201 . add_systems ( Render , prepare_ssr_pipelines. in_set ( RenderSystems :: Prepare ) )
194202 . add_systems (
195203 Render ,
196204 prepare_ssr_settings. in_set ( RenderSystems :: PrepareResources ) ,
197205 )
206+ // Note: we add this node here but then we add edges in
207+ // `add_screen_space_reflections_render_graph_edges`.
198208 . add_render_graph_node :: < ViewNodeRunner < ScreenSpaceReflectionsNode > > (
199209 Core3d ,
200210 NodePbr :: ScreenSpaceReflections ,
201211 ) ;
202212 }
213+ }
203214
204- fn finish ( & self , app : & mut App ) {
205- let Some ( render_app) = app. get_sub_app_mut ( RenderApp ) else {
206- return ;
207- } ;
215+ fn add_screen_space_reflections_render_graph_edges ( mut render_graph : ResMut < RenderGraph > ) {
216+ let subgraph = render_graph. sub_graph_mut ( Core3d ) ;
208217
209- render_app
210- . init_resource :: < ScreenSpaceReflectionsPipeline > ( )
211- . init_resource :: < SpecializedRenderPipelines < ScreenSpaceReflectionsPipeline > > ( ) ;
212-
213- // only reference the default deferred lighting pass
214- // if it has been added
215- let has_default_deferred_lighting_pass = render_app
216- . world_mut ( )
217- . resource_mut :: < RenderGraph > ( )
218- . sub_graph ( Core3d )
219- . get_node_state ( NodePbr :: DeferredLightingPass )
220- . is_ok ( ) ;
221-
222- if has_default_deferred_lighting_pass {
223- render_app. add_render_graph_edges (
224- Core3d ,
225- (
226- NodePbr :: DeferredLightingPass ,
227- NodePbr :: ScreenSpaceReflections ,
228- Node3d :: MainOpaquePass ,
229- ) ,
230- ) ;
231- } else {
232- render_app. add_render_graph_edges (
233- Core3d ,
234- ( NodePbr :: ScreenSpaceReflections , Node3d :: MainOpaquePass ) ,
235- ) ;
236- }
218+ subgraph. add_node_edge ( NodePbr :: ScreenSpaceReflections , Node3d :: MainOpaquePass ) ;
219+
220+ if subgraph
221+ . get_node_state ( NodePbr :: DeferredLightingPass )
222+ . is_ok ( )
223+ {
224+ subgraph. add_node_edge (
225+ NodePbr :: DeferredLightingPass ,
226+ NodePbr :: ScreenSpaceReflections ,
227+ ) ;
237228 }
238229}
239230
@@ -343,68 +334,69 @@ impl ViewNode for ScreenSpaceReflectionsNode {
343334 }
344335}
345336
346- impl FromWorld for ScreenSpaceReflectionsPipeline {
347- fn from_world ( world : & mut World ) -> Self {
348- let mesh_view_layouts = world. resource :: < MeshPipelineViewLayouts > ( ) . clone ( ) ;
349- let render_device = world. resource :: < RenderDevice > ( ) ;
350- let render_adapter = world. resource :: < RenderAdapter > ( ) ;
351-
352- // Create the bind group layout.
353- let bind_group_layout = render_device. create_bind_group_layout (
354- "SSR bind group layout" ,
355- & BindGroupLayoutEntries :: sequential (
356- ShaderStages :: FRAGMENT ,
357- (
358- binding_types:: texture_2d ( TextureSampleType :: Float { filterable : true } ) ,
359- binding_types:: sampler ( SamplerBindingType :: Filtering ) ,
360- binding_types:: sampler ( SamplerBindingType :: Filtering ) ,
361- binding_types:: sampler ( SamplerBindingType :: NonFiltering ) ,
362- ) ,
337+ pub fn init_screen_space_reflections_pipeline (
338+ mut commands : Commands ,
339+ render_device : Res < RenderDevice > ,
340+ render_adapter : Res < RenderAdapter > ,
341+ mesh_view_layouts : Res < MeshPipelineViewLayouts > ,
342+ fullscreen_shader : Res < FullscreenShader > ,
343+ asset_server : Res < AssetServer > ,
344+ ) {
345+ // Create the bind group layout.
346+ let bind_group_layout = render_device. create_bind_group_layout (
347+ "SSR bind group layout" ,
348+ & BindGroupLayoutEntries :: sequential (
349+ ShaderStages :: FRAGMENT ,
350+ (
351+ binding_types:: texture_2d ( TextureSampleType :: Float { filterable : true } ) ,
352+ binding_types:: sampler ( SamplerBindingType :: Filtering ) ,
353+ binding_types:: sampler ( SamplerBindingType :: Filtering ) ,
354+ binding_types:: sampler ( SamplerBindingType :: NonFiltering ) ,
363355 ) ,
364- ) ;
365-
366- // Create the samplers we need.
367-
368- let color_sampler = render_device. create_sampler ( & SamplerDescriptor {
369- label : "SSR color sampler" . into ( ) ,
370- address_mode_u : AddressMode :: ClampToEdge ,
371- address_mode_v : AddressMode :: ClampToEdge ,
372- mag_filter : FilterMode :: Linear ,
373- min_filter : FilterMode :: Linear ,
374- ..default ( )
375- } ) ;
376-
377- let depth_linear_sampler = render_device. create_sampler ( & SamplerDescriptor {
378- label : "SSR depth linear sampler" . into ( ) ,
379- address_mode_u : AddressMode :: ClampToEdge ,
380- address_mode_v : AddressMode :: ClampToEdge ,
381- mag_filter : FilterMode :: Linear ,
382- min_filter : FilterMode :: Linear ,
383- ..default ( )
384- } ) ;
385-
386- let depth_nearest_sampler = render_device. create_sampler ( & SamplerDescriptor {
387- label : "SSR depth nearest sampler" . into ( ) ,
388- address_mode_u : AddressMode :: ClampToEdge ,
389- address_mode_v : AddressMode :: ClampToEdge ,
390- mag_filter : FilterMode :: Nearest ,
391- min_filter : FilterMode :: Nearest ,
392- ..default ( )
393- } ) ;
356+ ) ,
357+ ) ;
394358
395- Self {
396- mesh_view_layouts,
397- color_sampler,
398- depth_linear_sampler,
399- depth_nearest_sampler,
400- bind_group_layout,
401- binding_arrays_are_usable : binding_arrays_are_usable ( render_device, render_adapter) ,
402- fullscreen_shader : world. resource :: < FullscreenShader > ( ) . clone ( ) ,
403- // Even though ssr was loaded using load_shader_library, we can still access it like a
404- // normal embedded asset (so we can use it as both a library or a kernel).
405- fragment_shader : load_embedded_asset ! ( world, "ssr.wgsl" ) ,
406- }
407- }
359+ // Create the samplers we need.
360+
361+ let color_sampler = render_device. create_sampler ( & SamplerDescriptor {
362+ label : "SSR color sampler" . into ( ) ,
363+ address_mode_u : AddressMode :: ClampToEdge ,
364+ address_mode_v : AddressMode :: ClampToEdge ,
365+ mag_filter : FilterMode :: Linear ,
366+ min_filter : FilterMode :: Linear ,
367+ ..default ( )
368+ } ) ;
369+
370+ let depth_linear_sampler = render_device. create_sampler ( & SamplerDescriptor {
371+ label : "SSR depth linear sampler" . into ( ) ,
372+ address_mode_u : AddressMode :: ClampToEdge ,
373+ address_mode_v : AddressMode :: ClampToEdge ,
374+ mag_filter : FilterMode :: Linear ,
375+ min_filter : FilterMode :: Linear ,
376+ ..default ( )
377+ } ) ;
378+
379+ let depth_nearest_sampler = render_device. create_sampler ( & SamplerDescriptor {
380+ label : "SSR depth nearest sampler" . into ( ) ,
381+ address_mode_u : AddressMode :: ClampToEdge ,
382+ address_mode_v : AddressMode :: ClampToEdge ,
383+ mag_filter : FilterMode :: Nearest ,
384+ min_filter : FilterMode :: Nearest ,
385+ ..default ( )
386+ } ) ;
387+
388+ commands. insert_resource ( ScreenSpaceReflectionsPipeline {
389+ mesh_view_layouts : mesh_view_layouts. clone ( ) ,
390+ color_sampler,
391+ depth_linear_sampler,
392+ depth_nearest_sampler,
393+ bind_group_layout,
394+ binding_arrays_are_usable : binding_arrays_are_usable ( & render_device, & render_adapter) ,
395+ fullscreen_shader : fullscreen_shader. clone ( ) ,
396+ // Even though ssr was loaded using load_shader_library, we can still access it like a
397+ // normal embedded asset (so we can use it as both a library or a kernel).
398+ fragment_shader : load_embedded_asset ! ( asset_server. as_ref( ) , "ssr.wgsl" ) ,
399+ } ) ;
408400}
409401
410402/// Sets up screen space reflection pipelines for each applicable view.
0 commit comments