Closed
Description
- Setting up a render node in Plugin::build() often looks like this:
// Create node
let taa_node = TAANode::new(&mut render_app.world);
// Get core_3d subgraph
let mut graph = render_app.world.resource_mut::<RenderGraph>();
let draw_3d_graph = graph
.get_sub_graph_mut(crate::core_3d::graph::NAME)
.unwrap();
// Add node, connect to view
draw_3d_graph.add_node(draw_3d_graph::node::TAA, taa_node);
draw_3d_graph.add_slot_edge(
draw_3d_graph.input_node().id,
crate::core_3d::graph::input::VIEW_ENTITY,
draw_3d_graph::node::TAA,
TAANode::IN_VIEW,
);
// Order nodes: MAIN_PASS -> TAA -> BLOOM -> TONEMAPPING
draw_3d_graph.add_node_edge(
crate::core_3d::graph::node::MAIN_PASS,
draw_3d_graph::node::TAA,
);
draw_3d_graph.add_node_edge(draw_3d_graph::node::TAA, crate::core_3d::graph::node::BLOOM);
draw_3d_graph.add_node_edge(
draw_3d_graph::node::TAA,
crate::core_3d::graph::node::TONEMAPPING,
);
We could add a helper to simplify it to something like this:
render_app.add_view_node<TAANode>(
subgraph: crate::core_3d::graph::NAME,
name: draw_3d_graph::node::TAA,
order: &[
crate::core_3d::graph::node::MAIN_PASS,
draw_3d_graph::node::TAA,
crate::core_3d::graph::node::BLOOM,
crate::core_3d::graph::node::TONEMAPPING,
],
);
- Declaring a render Node often looks like this:
struct TAANode {
view_query: QueryState<(
&'static ExtractedCamera,
&'static ViewTarget,
&'static TAAHistoryTextures,
&'static ViewPrepassTextures,
&'static TAAPipelineId,
)>,
}
impl TAANode {
const IN_VIEW: &'static str = "view";
fn new(world: &mut World) -> Self {
Self {
view_query: QueryState::new(world),
}
}
}
impl Node for TAANode {
fn input(&self) -> Vec<SlotInfo> {
vec![SlotInfo::new(Self::IN_VIEW, SlotType::Entity)]
}
fn update(&mut self, world: &mut World) {
self.view_query.update_archetypes(world);
}
fn run(
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
// Trace span
#[cfg(feature = "trace")]
let _taa_span = info_span!("taa").entered();
// Get view_query
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let (
Ok((camera, view_target, taa_history_textures, prepass_textures, taa_pipeline_id)),
Some(pipelines),
Some(pipeline_cache),
) = (
self.view_query.get_manual(world, view_entity),
world.get_resource::<TAAPipeline>(),
world.get_resource::<PipelineCache>(),
) else {
return Ok(());
};
// ...
}
}
We could provide an easier and more ergonomic Node impl:
struct TAANode {
view_query: QueryState<(
&'static ExtractedCamera,
&'static ViewTarget,
&'static TAAHistoryTextures,
&'static ViewPrepassTextures,
&'static TAAPipelineId,
)>,
// If possible, allow resource access declaratively
taa_pipeline: Res<TAAPipeline>,
pipeline_cache: Res<PipelineCache>,
}
impl SimpleNode for TAANode {
fn run(
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
// Automatically get view_query
((camera, view_target, taa_history_textures, ...)): (...),
) -> Result<(), NodeRunError> {
// Trace span automatically added
// ...
}
}