Clean up 2d render phases (#12982)
# Objective Currently, the 2d pipeline only has a transparent pass that is used for everything. I want to have separate passes for opaque/alpha mask/transparent meshes just like in 3d. This PR does the basic work to start adding new phases to the 2d pipeline and get the current setup a bit closer to 3d. ## Solution - Use `ViewNode` for `MainTransparentPass2dNode` - Added `Node2d::StartMainPass`, `Node2d::EndMainPass` - Rename everything to clarify that the main pass is currently the transparent pass --- ## Changelog - Added `Node2d::StartMainPass`, `Node2d::EndMainPass` ## Migration Guide If you were using `Node2d::MainPass` to order your own custom render node. You now need to order it relative to `Node2d::StartMainPass` or `Node2d::EndMainPass`.
This commit is contained in:
		
							parent
							
								
									0dddfa07ab
								
							
						
					
					
						commit
						64e1a7835a
					
				@ -81,7 +81,7 @@ impl Plugin for BloomPlugin {
 | 
			
		||||
            .add_render_graph_node::<ViewNodeRunner<BloomNode>>(Core2d, Node2d::Bloom)
 | 
			
		||||
            .add_render_graph_edges(
 | 
			
		||||
                Core2d,
 | 
			
		||||
                (Node2d::MainPass, Node2d::Bloom, Node2d::Tonemapping),
 | 
			
		||||
                (Node2d::EndMainPass, Node2d::Bloom, Node2d::Tonemapping),
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,67 +3,49 @@ use bevy_ecs::prelude::*;
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    camera::ExtractedCamera,
 | 
			
		||||
    diagnostic::RecordDiagnostics,
 | 
			
		||||
    render_graph::{Node, NodeRunError, RenderGraphContext},
 | 
			
		||||
    render_graph::{NodeRunError, RenderGraphContext, ViewNode},
 | 
			
		||||
    render_phase::SortedRenderPhase,
 | 
			
		||||
    render_resource::RenderPassDescriptor,
 | 
			
		||||
    renderer::RenderContext,
 | 
			
		||||
    view::{ExtractedView, ViewTarget},
 | 
			
		||||
    view::ViewTarget,
 | 
			
		||||
};
 | 
			
		||||
#[cfg(feature = "trace")]
 | 
			
		||||
use bevy_utils::tracing::info_span;
 | 
			
		||||
 | 
			
		||||
pub struct MainPass2dNode {
 | 
			
		||||
    query: QueryState<
 | 
			
		||||
        (
 | 
			
		||||
            &'static ExtractedCamera,
 | 
			
		||||
            &'static SortedRenderPhase<Transparent2d>,
 | 
			
		||||
            &'static ViewTarget,
 | 
			
		||||
        ),
 | 
			
		||||
        With<ExtractedView>,
 | 
			
		||||
    >,
 | 
			
		||||
}
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct MainTransparentPass2dNode {}
 | 
			
		||||
 | 
			
		||||
impl FromWorld for MainPass2dNode {
 | 
			
		||||
    fn from_world(world: &mut World) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            query: world.query_filtered(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl ViewNode for MainTransparentPass2dNode {
 | 
			
		||||
    type ViewQuery = (
 | 
			
		||||
        &'static ExtractedCamera,
 | 
			
		||||
        &'static SortedRenderPhase<Transparent2d>,
 | 
			
		||||
        &'static ViewTarget,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
impl Node for MainPass2dNode {
 | 
			
		||||
    fn update(&mut self, world: &mut World) {
 | 
			
		||||
        self.query.update_archetypes(world);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn run(
 | 
			
		||||
    fn run<'w>(
 | 
			
		||||
        &self,
 | 
			
		||||
        graph: &mut RenderGraphContext,
 | 
			
		||||
        render_context: &mut RenderContext,
 | 
			
		||||
        world: &World,
 | 
			
		||||
        render_context: &mut RenderContext<'w>,
 | 
			
		||||
        (camera, transparent_phase, target): bevy_ecs::query::QueryItem<'w, Self::ViewQuery>,
 | 
			
		||||
        world: &'w World,
 | 
			
		||||
    ) -> Result<(), NodeRunError> {
 | 
			
		||||
        let view_entity = graph.view_entity();
 | 
			
		||||
        let Ok((camera, transparent_phase, target)) = self.query.get_manual(world, view_entity)
 | 
			
		||||
        else {
 | 
			
		||||
            // no target
 | 
			
		||||
            return Ok(());
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
        if !transparent_phase.items.is_empty() {
 | 
			
		||||
            #[cfg(feature = "trace")]
 | 
			
		||||
            let _main_pass_2d = info_span!("main_pass_2d").entered();
 | 
			
		||||
            let _main_pass_2d = info_span!("main_transparent_pass_2d").entered();
 | 
			
		||||
 | 
			
		||||
            let diagnostics = render_context.diagnostic_recorder();
 | 
			
		||||
 | 
			
		||||
            let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
 | 
			
		||||
                label: Some("main_pass_2d"),
 | 
			
		||||
                label: Some("main_transparent_pass_2d"),
 | 
			
		||||
                color_attachments: &[Some(target.get_color_attachment())],
 | 
			
		||||
                depth_stencil_attachment: None,
 | 
			
		||||
                timestamp_writes: None,
 | 
			
		||||
                occlusion_query_set: None,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            let pass_span = diagnostics.pass_span(&mut render_pass, "main_pass_2d");
 | 
			
		||||
            let pass_span = diagnostics.pass_span(&mut render_pass, "main_transparent_pass_2d");
 | 
			
		||||
 | 
			
		||||
            if let Some(viewport) = camera.viewport.as_ref() {
 | 
			
		||||
                render_pass.set_camera_viewport(viewport);
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
mod camera_2d;
 | 
			
		||||
mod main_pass_2d_node;
 | 
			
		||||
mod main_transparent_pass_2d_node;
 | 
			
		||||
 | 
			
		||||
pub mod graph {
 | 
			
		||||
    use bevy_render::render_graph::{RenderLabel, RenderSubGraph};
 | 
			
		||||
@ -14,7 +14,9 @@ pub mod graph {
 | 
			
		||||
    #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
 | 
			
		||||
    pub enum Node2d {
 | 
			
		||||
        MsaaWriteback,
 | 
			
		||||
        MainPass,
 | 
			
		||||
        StartMainPass,
 | 
			
		||||
        MainTransparentPass,
 | 
			
		||||
        EndMainPass,
 | 
			
		||||
        Bloom,
 | 
			
		||||
        Tonemapping,
 | 
			
		||||
        Fxaa,
 | 
			
		||||
@ -27,7 +29,7 @@ pub mod graph {
 | 
			
		||||
use std::ops::Range;
 | 
			
		||||
 | 
			
		||||
pub use camera_2d::*;
 | 
			
		||||
pub use main_pass_2d_node::*;
 | 
			
		||||
pub use main_transparent_pass_2d_node::*;
 | 
			
		||||
 | 
			
		||||
use bevy_app::{App, Plugin};
 | 
			
		||||
use bevy_ecs::prelude::*;
 | 
			
		||||
@ -68,14 +70,21 @@ impl Plugin for Core2dPlugin {
 | 
			
		||||
 | 
			
		||||
        render_app
 | 
			
		||||
            .add_render_sub_graph(Core2d)
 | 
			
		||||
            .add_render_graph_node::<MainPass2dNode>(Core2d, Node2d::MainPass)
 | 
			
		||||
            .add_render_graph_node::<EmptyNode>(Core2d, Node2d::StartMainPass)
 | 
			
		||||
            .add_render_graph_node::<ViewNodeRunner<MainTransparentPass2dNode>>(
 | 
			
		||||
                Core2d,
 | 
			
		||||
                Node2d::MainTransparentPass,
 | 
			
		||||
            )
 | 
			
		||||
            .add_render_graph_node::<EmptyNode>(Core2d, Node2d::EndMainPass)
 | 
			
		||||
            .add_render_graph_node::<ViewNodeRunner<TonemappingNode>>(Core2d, Node2d::Tonemapping)
 | 
			
		||||
            .add_render_graph_node::<EmptyNode>(Core2d, Node2d::EndMainPassPostProcessing)
 | 
			
		||||
            .add_render_graph_node::<ViewNodeRunner<UpscalingNode>>(Core2d, Node2d::Upscaling)
 | 
			
		||||
            .add_render_graph_edges(
 | 
			
		||||
                Core2d,
 | 
			
		||||
                (
 | 
			
		||||
                    Node2d::MainPass,
 | 
			
		||||
                    Node2d::StartMainPass,
 | 
			
		||||
                    Node2d::MainTransparentPass,
 | 
			
		||||
                    Node2d::EndMainPass,
 | 
			
		||||
                    Node2d::Tonemapping,
 | 
			
		||||
                    Node2d::EndMainPassPostProcessing,
 | 
			
		||||
                    Node2d::Upscaling,
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ impl Plugin for MsaaWritebackPlugin {
 | 
			
		||||
        {
 | 
			
		||||
            render_app
 | 
			
		||||
                .add_render_graph_node::<MsaaWritebackNode>(Core2d, Node2d::MsaaWriteback)
 | 
			
		||||
                .add_render_graph_edge(Core2d, Node2d::MsaaWriteback, Node2d::MainPass);
 | 
			
		||||
                .add_render_graph_edge(Core2d, Node2d::MsaaWriteback, Node2d::StartMainPass);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            render_app
 | 
			
		||||
 | 
			
		||||
@ -389,7 +389,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (view, visible_entities, tonemapping, dither, mut transparent_phase) in &mut views {
 | 
			
		||||
        let draw_transparent_pbr = transparent_draw_functions.read().id::<DrawMaterial2d<M>>();
 | 
			
		||||
        let draw_transparent_2d = transparent_draw_functions.read().id::<DrawMaterial2d<M>>();
 | 
			
		||||
 | 
			
		||||
        let mut view_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples())
 | 
			
		||||
            | Mesh2dPipelineKey::from_hdr(view.hdr);
 | 
			
		||||
@ -410,7 +410,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
 | 
			
		||||
            let Some(mesh_instance) = render_mesh_instances.get_mut(visible_entity) else {
 | 
			
		||||
                continue;
 | 
			
		||||
            };
 | 
			
		||||
            let Some(material2d) = render_materials.get(*material_asset_id) else {
 | 
			
		||||
            let Some(material_2d) = render_materials.get(*material_asset_id) else {
 | 
			
		||||
                continue;
 | 
			
		||||
            };
 | 
			
		||||
            let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else {
 | 
			
		||||
@ -424,7 +424,7 @@ pub fn queue_material2d_meshes<M: Material2d>(
 | 
			
		||||
                &material2d_pipeline,
 | 
			
		||||
                Material2dKey {
 | 
			
		||||
                    mesh_key,
 | 
			
		||||
                    bind_group_data: material2d.key.clone(),
 | 
			
		||||
                    bind_group_data: material_2d.key.clone(),
 | 
			
		||||
                },
 | 
			
		||||
                &mesh.layout,
 | 
			
		||||
            );
 | 
			
		||||
@ -437,18 +437,18 @@ pub fn queue_material2d_meshes<M: Material2d>(
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            mesh_instance.material_bind_group_id = material2d.get_bind_group_id();
 | 
			
		||||
            mesh_instance.material_bind_group_id = material_2d.get_bind_group_id();
 | 
			
		||||
 | 
			
		||||
            let mesh_z = mesh_instance.transforms.transform.translation.z;
 | 
			
		||||
            transparent_phase.add(Transparent2d {
 | 
			
		||||
                entity: *visible_entity,
 | 
			
		||||
                draw_function: draw_transparent_pbr,
 | 
			
		||||
                draw_function: draw_transparent_2d,
 | 
			
		||||
                pipeline: pipeline_id,
 | 
			
		||||
                // NOTE: Back-to-front ordering for transparent with ascending sort means far should have the
 | 
			
		||||
                // lowest sort key and getting closer should increase. As we have
 | 
			
		||||
                // -z in front of the camera, the largest distance is -far with values increasing toward the
 | 
			
		||||
                // camera. As such we can just use mesh_z as the distance
 | 
			
		||||
                sort_key: FloatOrd(mesh_z + material2d.depth_bias),
 | 
			
		||||
                sort_key: FloatOrd(mesh_z + material_2d.depth_bias),
 | 
			
		||||
                // Batching is done in batch_and_prepare_render_phase
 | 
			
		||||
                batch_range: 0..1,
 | 
			
		||||
                extra_index: PhaseItemExtraIndex::NONE,
 | 
			
		||||
 | 
			
		||||
@ -126,7 +126,7 @@ pub fn build_ui_render(app: &mut App) {
 | 
			
		||||
    if let Some(graph_2d) = graph.get_sub_graph_mut(Core2d) {
 | 
			
		||||
        graph_2d.add_sub_graph(SubGraphUi, ui_graph_2d);
 | 
			
		||||
        graph_2d.add_node(NodeUi::UiPass, RunGraphOnViewNode::new(SubGraphUi));
 | 
			
		||||
        graph_2d.add_node_edge(Node2d::MainPass, NodeUi::UiPass);
 | 
			
		||||
        graph_2d.add_node_edge(Node2d::EndMainPass, NodeUi::UiPass);
 | 
			
		||||
        graph_2d.add_node_edge(Node2d::EndMainPassPostProcessing, NodeUi::UiPass);
 | 
			
		||||
        graph_2d.add_node_edge(NodeUi::UiPass, Node2d::Upscaling);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user