Skip to content

Commit 70e61bd

Browse files
committed
add custom sub_graph and more docs
1 parent 6596a79 commit 70e61bd

File tree

3 files changed

+66
-27
lines changed

3 files changed

+66
-27
lines changed

crates/bevy_core_pipeline/src/fullscreen_material.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
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
37
use std::marker::PhantomData;
48

5-
use crate::{core_3d::graph::Core3d, FullscreenShader};
9+
use crate::FullscreenShader;
610
use bevy_app::{App, Plugin};
711
use bevy_asset::AssetServer;
812
use 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
8690
pub 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

168192
impl<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

examples/shader/fullscreen_material.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
55
use bevy::{
66
core_pipeline::{
7-
core_3d::graph::Node3d,
7+
core_3d::graph::{Core3d, Node3d},
88
fullscreen_material::{FullscreenMaterial, FullscreenMaterialPlugin},
99
},
1010
prelude::*,
1111
shader::ShaderRef,
1212
};
1313
use bevy_render::{
1414
extract_component::ExtractComponent,
15-
render_graph::{InternedRenderLabel, RenderLabel},
15+
render_graph::{InternedRenderLabel, RenderLabel, RenderSubGraph},
1616
render_resource::ShaderType,
1717
};
1818

1919
fn main() {
2020
App::new()
2121
.add_plugins((
2222
DefaultPlugins,
23-
FullscreenMaterialPlugin::<MyPostProcessing>::default(),
23+
FullscreenMaterialPlugin::<FullscreenEffect>::default(),
2424
))
2525
.add_systems(Startup, setup)
2626
.run();
@@ -35,7 +35,7 @@ fn setup(
3535
commands.spawn((
3636
Camera3d::default(),
3737
Transform::from_translation(Vec3::new(0.0, 0.0, 5.0)).looking_at(Vec3::default(), Vec3::Y),
38-
MyPostProcessing { data: 0.005 },
38+
FullscreenEffect { intensity: 0.005 },
3939
));
4040

4141
// cube
@@ -52,26 +52,44 @@ fn setup(
5252
}
5353

5454
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
55-
struct MyLabel;
55+
struct FullscreenEffectLabel;
5656

5757
#[derive(Component, ExtractComponent, Clone, Copy, ShaderType, Default)]
58-
struct MyPostProcessing {
59-
data: f32,
58+
struct FullscreenEffect {
59+
// For this example, this is used as the intensity of the effect, but you can pass in any valid
60+
// ShaderType
61+
//
62+
// In the future, you will be able to use a full bind group
63+
intensity: f32,
6064
}
6165

62-
impl FullscreenMaterial for MyPostProcessing {
66+
impl FullscreenMaterial for FullscreenEffect {
67+
// The shader that will be used
6368
fn fragment_shader() -> ShaderRef {
64-
"shaders/my_post_processing.wgsl".into()
69+
"shaders/fullscreen_effect.wgsl".into()
6570
}
6671

67-
fn node_label() -> InternedRenderLabel {
68-
MyLabel.intern()
72+
// The material needs to know the label that will be used for the render graph
73+
fn node_label() -> impl RenderLabel {
74+
FullscreenEffectLabel
6975
}
7076

77+
// The sub graph the effect will run in. In 2d, this will generally be [`Core2d`] and in 3d it will
78+
// be [`Core3d`]
79+
fn sub_graph() -> impl RenderSubGraph {
80+
Core3d
81+
}
82+
83+
// This let's you specify a list of edges used to order when your effect pass will run
84+
//
85+
// This example is a post processing effect so it will run after tonemapping but before the end
86+
// post processing pass.
87+
//
88+
// In 2d you would need to use [`Node2d`] instead of [`Node3d`]
7189
fn node_edges() -> Vec<InternedRenderLabel> {
7290
vec![
7391
Node3d::Tonemapping.intern(),
74-
MyLabel.intern(),
92+
Self::node_label().intern(),
7593
Node3d::EndMainPassPostProcessing.intern(),
7694
]
7795
}

0 commit comments

Comments
 (0)