@@ -4,10 +4,7 @@ use std::marker::PhantomData;
44
55use bevy_app:: { App , Plugin } ;
66use bevy_asset:: AssetServer ;
7- use bevy_core_pipeline:: {
8- core_3d:: graph:: { Core3d , Node3d } ,
9- FullscreenShader ,
10- } ;
7+ use bevy_core_pipeline:: { core_3d:: graph:: Core3d , FullscreenShader } ;
118use bevy_ecs:: {
129 component:: Component ,
1310 query:: QueryItem ,
@@ -22,7 +19,8 @@ use bevy_render::{
2219 UniformComponentPlugin ,
2320 } ,
2421 render_graph:: {
25- NodeRunError , RenderGraphContext , RenderGraphExt , RenderLabel , ViewNode , ViewNodeRunner ,
22+ InternedRenderLabel , NodeRunError , RenderGraph , RenderGraphContext , RenderGraphError ,
23+ RenderGraphExt , ViewNode , ViewNodeRunner ,
2624 } ,
2725 render_resource:: {
2826 binding_types:: { sampler, texture_2d, uniform_buffer} ,
@@ -38,8 +36,7 @@ use bevy_render::{
3836 RenderApp , RenderStartup ,
3937} ;
4038use bevy_utils:: default;
41- #[ derive( Debug , Hash , PartialEq , Eq , Clone , RenderLabel ) ]
42- struct PostProcessLabel ;
39+ use tracing:: warn;
4340
4441#[ derive( Default ) ]
4542pub struct FullscreenMaterialPlugin < T : FullscreenMaterial > {
@@ -57,35 +54,49 @@ impl<T: FullscreenMaterial> Plugin for FullscreenMaterialPlugin<T> {
5754 } ;
5855 render_app. add_systems ( RenderStartup , init_pipeline :: < T > ) ;
5956
60- // TODO make this configurable so it's not hardcoded to 3d
61- render_app
62- . add_render_graph_node :: < ViewNodeRunner < FullscreenMaterialNode < T > > > (
63- Core3d ,
64- PostProcessLabel ,
65- )
66- . add_render_graph_edges (
67- Core3d ,
68- (
69- Node3d :: Tonemapping ,
70- // TODO make this configurable
71- PostProcessLabel ,
72- Node3d :: EndMainPassPostProcessing ,
73- ) ,
74- ) ;
57+ // TODO make this more configurable so it's not hardcoded to 3d
58+ render_app. add_render_graph_node :: < ViewNodeRunner < FullscreenMaterialNode < T > > > (
59+ Core3d ,
60+ T :: node_label ( ) ,
61+ ) ;
62+ // We can't use add_render_graph_edges because it doesn't accept a Vec<RenderLabel>
63+ 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 )
65+ {
66+ for window in T :: node_edges ( ) . windows ( 2 ) {
67+ let [ a, b] = window else {
68+ break ;
69+ } ;
70+ let Err ( err) = graph. try_add_node_edge ( * a, * b) else {
71+ continue ;
72+ } ;
73+ match err {
74+ // Already existing edges are very easy to produce with this api
75+ // and shouldn't cause a panic
76+ RenderGraphError :: EdgeAlreadyExists ( _) => { }
77+ _ => panic ! ( "{err:?}" ) ,
78+ }
79+ }
80+ } else {
81+ warn ! ( "Failed to add edges for FullscreenMaterial" ) ;
82+ } ;
7583 }
7684}
7785
7886pub trait FullscreenMaterial :
7987 Component + ExtractComponent + Clone + Copy + ShaderType + WriteInto + Default
8088{
8189 fn fragment_shader ( ) -> ShaderRef ;
90+ fn node_label ( ) -> InternedRenderLabel ;
91+ fn node_edges ( ) -> Vec < InternedRenderLabel > ;
8292}
8393
8494#[ derive( Resource ) ]
8595struct FullscreenMaterialPipeline {
8696 layout : BindGroupLayout ,
8797 sampler : Sampler ,
8898 pipeline_id : CachedRenderPipelineId ,
99+ pipeline_id_hdr : CachedRenderPipelineId ,
89100}
90101
91102fn init_pipeline < T : FullscreenMaterial > (
@@ -104,7 +115,6 @@ fn init_pipeline<T: FullscreenMaterial>(
104115 texture_2d ( TextureSampleType :: Float { filterable : true } ) ,
105116 // The sampler that will be used to sample the screen texture
106117 sampler ( SamplerBindingType :: Filtering ) ,
107- // The settings uniform that will control the effect
108118 uniform_buffer :: < T > ( true ) ,
109119 ) ,
110120 ) ,
@@ -121,13 +131,12 @@ fn init_pipeline<T: FullscreenMaterial>(
121131 } ;
122132 // Setup a fullscreen triangle for the vertex state.
123133 let vertex_state = fullscreen_shader. to_vertex_state ( ) ;
124- let pipeline_id = pipeline_cache . queue_render_pipeline ( RenderPipelineDescriptor {
134+ let mut desc = RenderPipelineDescriptor {
125135 label : Some ( "post_process_pipeline" . into ( ) ) ,
126136 layout : vec ! [ layout. clone( ) ] ,
127137 vertex : vertex_state,
128138 fragment : Some ( FragmentState {
129139 shader,
130- // TODO handle HDR
131140 targets : vec ! [ Some ( ColorTargetState {
132141 format: TextureFormat :: bevy_default( ) ,
133142 blend: None ,
@@ -136,11 +145,18 @@ fn init_pipeline<T: FullscreenMaterial>(
136145 ..default ( )
137146 } ) ,
138147 ..default ( )
139- } ) ;
148+ } ;
149+ let pipeline_id = pipeline_cache. queue_render_pipeline ( desc. clone ( ) ) ;
150+ desc. fragment . as_mut ( ) . unwrap ( ) . targets [ 0 ]
151+ . as_mut ( )
152+ . unwrap ( )
153+ . format = ViewTarget :: TEXTURE_FORMAT_HDR ;
154+ let pipeline_id_hdr = pipeline_cache. queue_render_pipeline ( desc) ;
140155 commands. insert_resource ( FullscreenMaterialPipeline {
141156 layout,
142157 sampler,
143158 pipeline_id,
159+ pipeline_id_hdr,
144160 } ) ;
145161}
146162
@@ -163,12 +179,16 @@ impl<T: FullscreenMaterial> ViewNode for FullscreenMaterialNode<T> {
163179 ( view_target, _post_process_settings, settings_index) : QueryItem < Self :: ViewQuery > ,
164180 world : & World ,
165181 ) -> Result < ( ) , NodeRunError > {
166- let post_process_pipeline = world. resource :: < FullscreenMaterialPipeline > ( ) ;
182+ let fullscreen_pipeline = world. resource :: < FullscreenMaterialPipeline > ( ) ;
167183
168184 let pipeline_cache = world. resource :: < PipelineCache > ( ) ;
185+ let pipeline_id = if view_target. is_hdr ( ) {
186+ fullscreen_pipeline. pipeline_id_hdr
187+ } else {
188+ fullscreen_pipeline. pipeline_id
189+ } ;
169190
170- let Some ( pipeline) = pipeline_cache. get_render_pipeline ( post_process_pipeline. pipeline_id )
171- else {
191+ let Some ( pipeline) = pipeline_cache. get_render_pipeline ( pipeline_id) else {
172192 return Ok ( ( ) ) ;
173193 } ;
174194
@@ -177,17 +197,16 @@ impl<T: FullscreenMaterial> ViewNode for FullscreenMaterialNode<T> {
177197 return Ok ( ( ) ) ;
178198 } ;
179199
200+ // We should maybe rename this because this can be used for other reasons that aren't
201+ // post-processing
180202 let post_process = view_target. post_process_write ( ) ;
181203
182204 let bind_group = render_context. render_device ( ) . create_bind_group (
183205 "post_process_bind_group" ,
184- & post_process_pipeline . layout ,
206+ & fullscreen_pipeline . layout ,
185207 & BindGroupEntries :: sequential ( (
186- // Make sure to use the source view
187208 post_process. source ,
188- // Use the sampler created for the pipeline
189- & post_process_pipeline. sampler ,
190- // Set the settings binding
209+ & fullscreen_pipeline. sampler ,
191210 settings_binding. clone ( ) ,
192211 ) ) ,
193212 ) ;
0 commit comments