1- //! This is mostly a pluginify version of the custom_post_processing example
1+ //! This is mostly a pluginified version of the custom_post_processing example
2+ //!
3+ //! The plugin will create a new node that runs a fullscreen triangle.
4+ //!
5+ //! Users need to use the [`FullscreenMaterial`] trait to define the parameters like the graph label or the graph ordering.
26
37use std:: marker:: PhantomData ;
48
5- use crate :: { core_3d :: graph :: Core3d , FullscreenShader } ;
9+ use crate :: FullscreenShader ;
610use bevy_app:: { App , Plugin } ;
711use bevy_asset:: AssetServer ;
812use bevy_ecs:: {
@@ -20,7 +24,7 @@ use bevy_render::{
2024 } ,
2125 render_graph:: {
2226 InternedRenderLabel , NodeRunError , RenderGraph , RenderGraphContext , RenderGraphError ,
23- RenderGraphExt , ViewNode , ViewNodeRunner ,
27+ RenderGraphExt , RenderLabel , RenderSubGraph , ViewNode , ViewNodeRunner ,
2428 } ,
2529 render_resource:: {
2630 binding_types:: { sampler, texture_2d, uniform_buffer} ,
@@ -54,14 +58,13 @@ impl<T: FullscreenMaterial> Plugin for FullscreenMaterialPlugin<T> {
5458 } ;
5559 render_app. add_systems ( RenderStartup , init_pipeline :: < T > ) ;
5660
57- // TODO make this more configurable so it's not hardcoded to 3d
5861 render_app. add_render_graph_node :: < ViewNodeRunner < FullscreenMaterialNode < T > > > (
59- Core3d ,
62+ T :: sub_graph ( ) ,
6063 T :: node_label ( ) ,
6164 ) ;
6265 // We can't use add_render_graph_edges because it doesn't accept a Vec<RenderLabel>
6366 if let Some ( mut render_graph) = render_app. world_mut ( ) . get_resource_mut :: < RenderGraph > ( )
64- && let Some ( graph) = render_graph. get_sub_graph_mut ( Core3d )
67+ && let Some ( graph) = render_graph. get_sub_graph_mut ( T :: sub_graph ( ) )
6568 {
6669 for window in T :: node_edges ( ) . windows ( 2 ) {
6770 let [ a, b] = window else {
@@ -83,11 +86,30 @@ impl<T: FullscreenMaterial> Plugin for FullscreenMaterialPlugin<T> {
8386 }
8487}
8588
89+ /// A trait to define a material that will render to the entire screen using a fullscrene triangle
8690pub trait FullscreenMaterial :
8791 Component + ExtractComponent + Clone + Copy + ShaderType + WriteInto + Default
8892{
93+ /// The shader that will run on the entire screen using a fullscreen triangle
8994 fn fragment_shader ( ) -> ShaderRef ;
90- fn node_label ( ) -> InternedRenderLabel ;
95+ /// The sub_graph the effect will run in
96+ /// For 2d this is generally [`Core2d`] and for 3d it's [`Core3d`]
97+ fn sub_graph ( ) -> impl RenderSubGraph ;
98+ /// The label used to represent the render node that will run the pass
99+ fn node_label ( ) -> impl RenderLabel ;
100+ /// The list of node_edges. In 3d, for a post processing effect, it would look like this:
101+ ///
102+ /// ```rust
103+ /// vec![
104+ /// Node3d::Tonemapping.intern(),
105+ /// Self::sub_graph().intern(), // <--- your own label here
106+ /// Node3d::EndMainPassPostProcessing.intern(),
107+ /// ]
108+ /// ```
109+ ///
110+ /// This tell the render graph to run your fullscreen effect after the tonemapping pass but
111+ /// before the end of post processing. For 2d, it would be the same but using Node2d. You can
112+ /// specify any edges you want but make sure to include your own label.
91113 fn node_edges ( ) -> Vec < InternedRenderLabel > ;
92114}
93115
@@ -115,6 +137,8 @@ fn init_pipeline<T: FullscreenMaterial>(
115137 texture_2d ( TextureSampleType :: Float { filterable : true } ) ,
116138 // The sampler that will be used to sample the screen texture
117139 sampler ( SamplerBindingType :: Filtering ) ,
140+ // We use a uniform buffer so users can pass some data to the effect
141+ // Eventually we should just use a separate bind group for user data
118142 uniform_buffer :: < T > ( true ) ,
119143 ) ,
120144 ) ,
@@ -166,17 +190,14 @@ struct FullscreenMaterialNode<T: FullscreenMaterial> {
166190}
167191
168192impl < T : FullscreenMaterial > ViewNode for FullscreenMaterialNode < T > {
169- type ViewQuery = (
170- & ' static ViewTarget ,
171- & ' static T ,
172- & ' static DynamicUniformIndex < T > ,
173- ) ;
193+ // TODO we should expose the depth buffer and the gbuffer if using deferred
194+ type ViewQuery = ( & ' static ViewTarget , & ' static DynamicUniformIndex < T > ) ;
174195
175196 fn run < ' w > (
176197 & self ,
177198 _graph : & mut RenderGraphContext ,
178199 render_context : & mut RenderContext ,
179- ( view_target, _post_process_settings , settings_index) : QueryItem < Self :: ViewQuery > ,
200+ ( view_target, settings_index) : QueryItem < Self :: ViewQuery > ,
180201 world : & World ,
181202 ) -> Result < ( ) , NodeRunError > {
182203 let fullscreen_pipeline = world. resource :: < FullscreenMaterialPipeline > ( ) ;
@@ -192,8 +213,8 @@ impl<T: FullscreenMaterial> ViewNode for FullscreenMaterialNode<T> {
192213 return Ok ( ( ) ) ;
193214 } ;
194215
195- let settings_uniforms = world. resource :: < ComponentUniforms < T > > ( ) ;
196- let Some ( settings_binding) = settings_uniforms . uniforms ( ) . binding ( ) else {
216+ let data_uniforms = world. resource :: < ComponentUniforms < T > > ( ) ;
217+ let Some ( settings_binding) = data_uniforms . uniforms ( ) . binding ( ) else {
197218 return Ok ( ( ) ) ;
198219 } ;
199220
0 commit comments