Split opaque and transparent phases (#8090)
# Objective Fixes #8089. ## Solution Splits the MainPass3dNode into 2 nodes, one for the opaque + alpha passes and one for the transparent pass. --- ## Changelog - Split MainPass3dNode into MainOpaquePass3dNode and MainTransparentPass3dNode - Combine opaque and alpha phases in MainOpaquePass3dNode into one pass - Create `START_MAIN_PASS` and `END_MAIN_PASS` empty nodes as labels - Main pass becomes `START_MAIN_PASS -> MAIN_OPAQUE_PASS -> MAIN_TRANSPARENT_PASS -> END_MAIN_PASS` ## Migration Guide Nodes that previously added edges involving `MAIN_PASS` should now add edges to or from `START_MAIN_PASS` or `END_MAIN_PASS` respectively.
This commit is contained in:
parent
53667dea56
commit
ae31361949
@ -83,7 +83,7 @@ impl Plugin for BloomPlugin {
|
|||||||
draw_3d_graph.add_node(core_3d::graph::node::BLOOM, bloom_node);
|
draw_3d_graph.add_node(core_3d::graph::node::BLOOM, bloom_node);
|
||||||
// MAIN_PASS -> BLOOM -> TONEMAPPING
|
// MAIN_PASS -> BLOOM -> TONEMAPPING
|
||||||
draw_3d_graph.add_node_edge(
|
draw_3d_graph.add_node_edge(
|
||||||
crate::core_3d::graph::node::MAIN_PASS,
|
crate::core_3d::graph::node::END_MAIN_PASS,
|
||||||
core_3d::graph::node::BLOOM,
|
core_3d::graph::node::BLOOM,
|
||||||
);
|
);
|
||||||
draw_3d_graph.add_node_edge(
|
draw_3d_graph.add_node_edge(
|
||||||
|
|||||||
@ -0,0 +1,126 @@
|
|||||||
|
use crate::{
|
||||||
|
clear_color::{ClearColor, ClearColorConfig},
|
||||||
|
core_3d::{Camera3d, Opaque3d},
|
||||||
|
prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass},
|
||||||
|
};
|
||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use bevy_render::{
|
||||||
|
camera::ExtractedCamera,
|
||||||
|
render_graph::{Node, NodeRunError, RenderGraphContext},
|
||||||
|
render_phase::RenderPhase,
|
||||||
|
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
||||||
|
renderer::RenderContext,
|
||||||
|
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
use super::{AlphaMask3d, Camera3dDepthLoadOp};
|
||||||
|
|
||||||
|
/// A [`Node`] that runs the [`Opaque3d`] and [`AlphaMask3d`] [`RenderPhase`].
|
||||||
|
pub struct MainOpaquePass3dNode {
|
||||||
|
query: QueryState<
|
||||||
|
(
|
||||||
|
&'static ExtractedCamera,
|
||||||
|
&'static RenderPhase<Opaque3d>,
|
||||||
|
&'static RenderPhase<AlphaMask3d>,
|
||||||
|
&'static Camera3d,
|
||||||
|
&'static ViewTarget,
|
||||||
|
&'static ViewDepthTexture,
|
||||||
|
Option<&'static DepthPrepass>,
|
||||||
|
Option<&'static NormalPrepass>,
|
||||||
|
Option<&'static MotionVectorPrepass>,
|
||||||
|
),
|
||||||
|
With<ExtractedView>,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainOpaquePass3dNode {
|
||||||
|
pub fn new(world: &mut World) -> Self {
|
||||||
|
Self {
|
||||||
|
query: world.query_filtered(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for MainOpaquePass3dNode {
|
||||||
|
fn update(&mut self, world: &mut World) {
|
||||||
|
self.query.update_archetypes(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
graph: &mut RenderGraphContext,
|
||||||
|
render_context: &mut RenderContext,
|
||||||
|
world: &World,
|
||||||
|
) -> Result<(), NodeRunError> {
|
||||||
|
let view_entity = graph.view_entity();
|
||||||
|
let Ok((
|
||||||
|
camera,
|
||||||
|
opaque_phase,
|
||||||
|
alpha_mask_phase,
|
||||||
|
camera_3d,
|
||||||
|
target,
|
||||||
|
depth,
|
||||||
|
depth_prepass,
|
||||||
|
normal_prepass,
|
||||||
|
motion_vector_prepass
|
||||||
|
)) = self.query.get_manual(world, view_entity) else {
|
||||||
|
// No window
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the opaque pass, sorted front-to-back
|
||||||
|
// NOTE: Scoped to drop the mutable borrow of render_context
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
let _main_opaque_pass_3d_span = info_span!("main_opaque_pass_3d").entered();
|
||||||
|
|
||||||
|
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||||
|
label: Some("main_opaque_pass_3d"),
|
||||||
|
// NOTE: The opaque pass loads the color
|
||||||
|
// buffer as well as writing to it.
|
||||||
|
color_attachments: &[Some(target.get_color_attachment(Operations {
|
||||||
|
load: match camera_3d.clear_color {
|
||||||
|
ClearColorConfig::Default => {
|
||||||
|
LoadOp::Clear(world.resource::<ClearColor>().0.into())
|
||||||
|
}
|
||||||
|
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
|
||||||
|
ClearColorConfig::None => LoadOp::Load,
|
||||||
|
},
|
||||||
|
store: true,
|
||||||
|
}))],
|
||||||
|
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||||
|
view: &depth.view,
|
||||||
|
// NOTE: The opaque main pass loads the depth buffer and possibly overwrites it
|
||||||
|
depth_ops: Some(Operations {
|
||||||
|
load: if depth_prepass.is_some()
|
||||||
|
|| normal_prepass.is_some()
|
||||||
|
|| motion_vector_prepass.is_some()
|
||||||
|
{
|
||||||
|
// if any prepass runs, it will generate a depth buffer so we should use it,
|
||||||
|
// even if only the normal_prepass is used.
|
||||||
|
Camera3dDepthLoadOp::Load
|
||||||
|
} else {
|
||||||
|
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections.
|
||||||
|
camera_3d.depth_load_op.clone()
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
store: true,
|
||||||
|
}),
|
||||||
|
stencil_ops: None,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
|
render_pass.set_camera_viewport(viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
opaque_phase.render(&mut render_pass, world, view_entity);
|
||||||
|
|
||||||
|
if !alpha_mask_phase.items.is_empty() {
|
||||||
|
alpha_mask_phase.render(&mut render_pass, world, view_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,213 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
clear_color::{ClearColor, ClearColorConfig},
|
|
||||||
core_3d::{AlphaMask3d, Camera3d, Opaque3d, Transparent3d},
|
|
||||||
prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass},
|
|
||||||
};
|
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
use bevy_render::{
|
|
||||||
camera::ExtractedCamera,
|
|
||||||
render_graph::{Node, NodeRunError, RenderGraphContext},
|
|
||||||
render_phase::RenderPhase,
|
|
||||||
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
|
||||||
renderer::RenderContext,
|
|
||||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
|
||||||
};
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
use bevy_utils::tracing::info_span;
|
|
||||||
|
|
||||||
use super::Camera3dDepthLoadOp;
|
|
||||||
|
|
||||||
pub struct MainPass3dNode {
|
|
||||||
query: QueryState<
|
|
||||||
(
|
|
||||||
&'static ExtractedCamera,
|
|
||||||
&'static RenderPhase<Opaque3d>,
|
|
||||||
&'static RenderPhase<AlphaMask3d>,
|
|
||||||
&'static RenderPhase<Transparent3d>,
|
|
||||||
&'static Camera3d,
|
|
||||||
&'static ViewTarget,
|
|
||||||
&'static ViewDepthTexture,
|
|
||||||
Option<&'static DepthPrepass>,
|
|
||||||
Option<&'static NormalPrepass>,
|
|
||||||
Option<&'static MotionVectorPrepass>,
|
|
||||||
),
|
|
||||||
With<ExtractedView>,
|
|
||||||
>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MainPass3dNode {
|
|
||||||
pub fn new(world: &mut World) -> Self {
|
|
||||||
Self {
|
|
||||||
query: world.query_filtered(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for MainPass3dNode {
|
|
||||||
fn update(&mut self, world: &mut World) {
|
|
||||||
self.query.update_archetypes(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
graph: &mut RenderGraphContext,
|
|
||||||
render_context: &mut RenderContext,
|
|
||||||
world: &World,
|
|
||||||
) -> Result<(), NodeRunError> {
|
|
||||||
let view_entity = graph.view_entity();
|
|
||||||
let Ok((
|
|
||||||
camera,
|
|
||||||
opaque_phase,
|
|
||||||
alpha_mask_phase,
|
|
||||||
transparent_phase,
|
|
||||||
camera_3d,
|
|
||||||
target,
|
|
||||||
depth,
|
|
||||||
depth_prepass,
|
|
||||||
normal_prepass,
|
|
||||||
motion_vector_prepass,
|
|
||||||
)) = self.query.get_manual(world, view_entity) else {
|
|
||||||
// No window
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Always run opaque pass to ensure screen is cleared
|
|
||||||
{
|
|
||||||
// Run the opaque pass, sorted front-to-back
|
|
||||||
// NOTE: Scoped to drop the mutable borrow of render_context
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
let _main_opaque_pass_3d_span = info_span!("main_opaque_pass_3d").entered();
|
|
||||||
|
|
||||||
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
|
||||||
label: Some("main_opaque_pass_3d"),
|
|
||||||
// NOTE: The opaque pass loads the color
|
|
||||||
// buffer as well as writing to it.
|
|
||||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
|
||||||
load: match camera_3d.clear_color {
|
|
||||||
ClearColorConfig::Default => {
|
|
||||||
LoadOp::Clear(world.resource::<ClearColor>().0.into())
|
|
||||||
}
|
|
||||||
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
|
|
||||||
ClearColorConfig::None => LoadOp::Load,
|
|
||||||
},
|
|
||||||
store: true,
|
|
||||||
}))],
|
|
||||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
|
||||||
view: &depth.view,
|
|
||||||
// NOTE: The opaque main pass loads the depth buffer and possibly overwrites it
|
|
||||||
depth_ops: Some(Operations {
|
|
||||||
load: if depth_prepass.is_some()
|
|
||||||
|| normal_prepass.is_some()
|
|
||||||
|| motion_vector_prepass.is_some()
|
|
||||||
{
|
|
||||||
// if any prepass runs, it will generate a depth buffer so we should use it,
|
|
||||||
// even if only the normal_prepass is used.
|
|
||||||
Camera3dDepthLoadOp::Load
|
|
||||||
} else {
|
|
||||||
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections.
|
|
||||||
camera_3d.depth_load_op.clone()
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
store: true,
|
|
||||||
}),
|
|
||||||
stencil_ops: None,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
render_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
opaque_phase.render(&mut render_pass, world, view_entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !alpha_mask_phase.items.is_empty() {
|
|
||||||
// Run the alpha mask pass, sorted front-to-back
|
|
||||||
// NOTE: Scoped to drop the mutable borrow of render_context
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
let _main_alpha_mask_pass_3d_span = info_span!("main_alpha_mask_pass_3d").entered();
|
|
||||||
|
|
||||||
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
|
||||||
label: Some("main_alpha_mask_pass_3d"),
|
|
||||||
// NOTE: The alpha_mask pass loads the color buffer as well as overwriting it where appropriate.
|
|
||||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
|
||||||
load: LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}))],
|
|
||||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
|
||||||
view: &depth.view,
|
|
||||||
// NOTE: The alpha mask pass loads the depth buffer and possibly overwrites it
|
|
||||||
depth_ops: Some(Operations {
|
|
||||||
load: LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}),
|
|
||||||
stencil_ops: None,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
render_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
alpha_mask_phase.render(&mut render_pass, world, view_entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !transparent_phase.items.is_empty() {
|
|
||||||
// Run the transparent pass, sorted back-to-front
|
|
||||||
// NOTE: Scoped to drop the mutable borrow of render_context
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
let _main_transparent_pass_3d_span = info_span!("main_transparent_pass_3d").entered();
|
|
||||||
|
|
||||||
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
|
||||||
label: Some("main_transparent_pass_3d"),
|
|
||||||
// NOTE: The transparent pass loads the color buffer as well as overwriting it where appropriate.
|
|
||||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
|
||||||
load: LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}))],
|
|
||||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
|
||||||
view: &depth.view,
|
|
||||||
// NOTE: For the transparent pass we load the depth buffer. There should be no
|
|
||||||
// need to write to it, but store is set to `true` as a workaround for issue #3776,
|
|
||||||
// https://github.com/bevyengine/bevy/issues/3776
|
|
||||||
// so that wgpu does not clear the depth buffer.
|
|
||||||
// As the opaque and alpha mask passes run first, opaque meshes can occlude
|
|
||||||
// transparent ones.
|
|
||||||
depth_ops: Some(Operations {
|
|
||||||
load: LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}),
|
|
||||||
stencil_ops: None,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
render_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
|
|
||||||
transparent_phase.render(&mut render_pass, world, view_entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
|
||||||
// reset for the next render pass so add an empty render pass without a custom viewport
|
|
||||||
#[cfg(feature = "webgl")]
|
|
||||||
if camera.viewport.is_some() {
|
|
||||||
#[cfg(feature = "trace")]
|
|
||||||
let _reset_viewport_pass_3d = info_span!("reset_viewport_pass_3d").entered();
|
|
||||||
let pass_descriptor = RenderPassDescriptor {
|
|
||||||
label: Some("reset_viewport_pass_3d"),
|
|
||||||
color_attachments: &[Some(target.get_color_attachment(Operations {
|
|
||||||
load: LoadOp::Load,
|
|
||||||
store: true,
|
|
||||||
}))],
|
|
||||||
depth_stencil_attachment: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
render_context
|
|
||||||
.command_encoder()
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
use crate::core_3d::Transparent3d;
|
||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use bevy_render::{
|
||||||
|
camera::ExtractedCamera,
|
||||||
|
render_graph::{Node, NodeRunError, RenderGraphContext},
|
||||||
|
render_phase::RenderPhase,
|
||||||
|
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
||||||
|
renderer::RenderContext,
|
||||||
|
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
use bevy_utils::tracing::info_span;
|
||||||
|
|
||||||
|
/// A [`Node`] that runs the [`Transparent3d`] [`RenderPhase`].
|
||||||
|
pub struct MainTransparentPass3dNode {
|
||||||
|
query: QueryState<
|
||||||
|
(
|
||||||
|
&'static ExtractedCamera,
|
||||||
|
&'static RenderPhase<Transparent3d>,
|
||||||
|
&'static ViewTarget,
|
||||||
|
&'static ViewDepthTexture,
|
||||||
|
),
|
||||||
|
With<ExtractedView>,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainTransparentPass3dNode {
|
||||||
|
pub fn new(world: &mut World) -> Self {
|
||||||
|
Self {
|
||||||
|
query: world.query_filtered(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node for MainTransparentPass3dNode {
|
||||||
|
fn update(&mut self, world: &mut World) {
|
||||||
|
self.query.update_archetypes(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
graph: &mut RenderGraphContext,
|
||||||
|
render_context: &mut RenderContext,
|
||||||
|
world: &World,
|
||||||
|
) -> Result<(), NodeRunError> {
|
||||||
|
let view_entity = graph.view_entity();
|
||||||
|
let Ok((
|
||||||
|
camera,
|
||||||
|
transparent_phase,
|
||||||
|
target,
|
||||||
|
depth,
|
||||||
|
)) = self.query.get_manual(world, view_entity) else {
|
||||||
|
// No window
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if !transparent_phase.items.is_empty() {
|
||||||
|
// Run the transparent pass, sorted back-to-front
|
||||||
|
// NOTE: Scoped to drop the mutable borrow of render_context
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
let _main_transparent_pass_3d_span = info_span!("main_transparent_pass_3d").entered();
|
||||||
|
|
||||||
|
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||||
|
label: Some("main_transparent_pass_3d"),
|
||||||
|
// NOTE: The transparent pass loads the color buffer as well as overwriting it where appropriate.
|
||||||
|
color_attachments: &[Some(target.get_color_attachment(Operations {
|
||||||
|
load: LoadOp::Load,
|
||||||
|
store: true,
|
||||||
|
}))],
|
||||||
|
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||||
|
view: &depth.view,
|
||||||
|
// NOTE: For the transparent pass we load the depth buffer. There should be no
|
||||||
|
// need to write to it, but store is set to `true` as a workaround for issue #3776,
|
||||||
|
// https://github.com/bevyengine/bevy/issues/3776
|
||||||
|
// so that wgpu does not clear the depth buffer.
|
||||||
|
// As the opaque and alpha mask passes run first, opaque meshes can occlude
|
||||||
|
// transparent ones.
|
||||||
|
depth_ops: Some(Operations {
|
||||||
|
load: LoadOp::Load,
|
||||||
|
store: true,
|
||||||
|
}),
|
||||||
|
stencil_ops: None,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(viewport) = camera.viewport.as_ref() {
|
||||||
|
render_pass.set_camera_viewport(viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
transparent_phase.render(&mut render_pass, world, view_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
||||||
|
// reset for the next render pass so add an empty render pass without a custom viewport
|
||||||
|
#[cfg(feature = "webgl")]
|
||||||
|
if camera.viewport.is_some() {
|
||||||
|
#[cfg(feature = "trace")]
|
||||||
|
let _reset_viewport_pass_3d = info_span!("reset_viewport_pass_3d").entered();
|
||||||
|
let pass_descriptor = RenderPassDescriptor {
|
||||||
|
label: Some("reset_viewport_pass_3d"),
|
||||||
|
color_attachments: &[Some(target.get_color_attachment(Operations {
|
||||||
|
load: LoadOp::Load,
|
||||||
|
store: true,
|
||||||
|
}))],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
render_context
|
||||||
|
.command_encoder()
|
||||||
|
.begin_render_pass(&pass_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
mod camera_3d;
|
mod camera_3d;
|
||||||
mod main_pass_3d_node;
|
mod main_opaque_pass_3d_node;
|
||||||
|
mod main_transparent_pass_3d_node;
|
||||||
|
|
||||||
pub mod graph {
|
pub mod graph {
|
||||||
pub const NAME: &str = "core_3d";
|
pub const NAME: &str = "core_3d";
|
||||||
@ -9,7 +10,10 @@ pub mod graph {
|
|||||||
pub mod node {
|
pub mod node {
|
||||||
pub const MSAA_WRITEBACK: &str = "msaa_writeback";
|
pub const MSAA_WRITEBACK: &str = "msaa_writeback";
|
||||||
pub const PREPASS: &str = "prepass";
|
pub const PREPASS: &str = "prepass";
|
||||||
pub const MAIN_PASS: &str = "main_pass";
|
pub const START_MAIN_PASS: &str = "start_main_pass";
|
||||||
|
pub const MAIN_OPAQUE_PASS: &str = "main_opaque_pass";
|
||||||
|
pub const MAIN_TRANSPARENT_PASS: &str = "main_transparent_pass";
|
||||||
|
pub const END_MAIN_PASS: &str = "end_main_pass";
|
||||||
pub const BLOOM: &str = "bloom";
|
pub const BLOOM: &str = "bloom";
|
||||||
pub const TONEMAPPING: &str = "tonemapping";
|
pub const TONEMAPPING: &str = "tonemapping";
|
||||||
pub const FXAA: &str = "fxaa";
|
pub const FXAA: &str = "fxaa";
|
||||||
@ -21,7 +25,8 @@ pub mod graph {
|
|||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
|
|
||||||
pub use camera_3d::*;
|
pub use camera_3d::*;
|
||||||
pub use main_pass_3d_node::*;
|
pub use main_opaque_pass_3d_node::*;
|
||||||
|
pub use main_transparent_pass_3d_node::*;
|
||||||
|
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
@ -82,20 +87,33 @@ impl Plugin for Core3dPlugin {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let prepass_node = PrepassNode::new(&mut render_app.world);
|
let prepass_node = PrepassNode::new(&mut render_app.world);
|
||||||
let pass_node_3d = MainPass3dNode::new(&mut render_app.world);
|
let opaque_node_3d = MainOpaquePass3dNode::new(&mut render_app.world);
|
||||||
|
let transparent_node_3d = MainTransparentPass3dNode::new(&mut render_app.world);
|
||||||
let tonemapping = TonemappingNode::new(&mut render_app.world);
|
let tonemapping = TonemappingNode::new(&mut render_app.world);
|
||||||
let upscaling = UpscalingNode::new(&mut render_app.world);
|
let upscaling = UpscalingNode::new(&mut render_app.world);
|
||||||
let mut graph = render_app.world.resource_mut::<RenderGraph>();
|
let mut graph = render_app.world.resource_mut::<RenderGraph>();
|
||||||
|
|
||||||
let mut draw_3d_graph = RenderGraph::default();
|
let mut draw_3d_graph = RenderGraph::default();
|
||||||
draw_3d_graph.add_node(graph::node::PREPASS, prepass_node);
|
draw_3d_graph.add_node(graph::node::PREPASS, prepass_node);
|
||||||
draw_3d_graph.add_node(graph::node::MAIN_PASS, pass_node_3d);
|
draw_3d_graph.add_node(graph::node::START_MAIN_PASS, EmptyNode);
|
||||||
|
draw_3d_graph.add_node(graph::node::MAIN_OPAQUE_PASS, opaque_node_3d);
|
||||||
|
draw_3d_graph.add_node(graph::node::MAIN_TRANSPARENT_PASS, transparent_node_3d);
|
||||||
|
draw_3d_graph.add_node(graph::node::END_MAIN_PASS, EmptyNode);
|
||||||
draw_3d_graph.add_node(graph::node::TONEMAPPING, tonemapping);
|
draw_3d_graph.add_node(graph::node::TONEMAPPING, tonemapping);
|
||||||
draw_3d_graph.add_node(graph::node::END_MAIN_PASS_POST_PROCESSING, EmptyNode);
|
draw_3d_graph.add_node(graph::node::END_MAIN_PASS_POST_PROCESSING, EmptyNode);
|
||||||
draw_3d_graph.add_node(graph::node::UPSCALING, upscaling);
|
draw_3d_graph.add_node(graph::node::UPSCALING, upscaling);
|
||||||
|
|
||||||
draw_3d_graph.add_node_edge(graph::node::PREPASS, graph::node::MAIN_PASS);
|
draw_3d_graph.add_node_edge(graph::node::PREPASS, graph::node::START_MAIN_PASS);
|
||||||
draw_3d_graph.add_node_edge(graph::node::MAIN_PASS, graph::node::TONEMAPPING);
|
draw_3d_graph.add_node_edge(graph::node::START_MAIN_PASS, graph::node::MAIN_OPAQUE_PASS);
|
||||||
|
draw_3d_graph.add_node_edge(
|
||||||
|
graph::node::MAIN_OPAQUE_PASS,
|
||||||
|
graph::node::MAIN_TRANSPARENT_PASS,
|
||||||
|
);
|
||||||
|
draw_3d_graph.add_node_edge(
|
||||||
|
graph::node::MAIN_TRANSPARENT_PASS,
|
||||||
|
graph::node::END_MAIN_PASS,
|
||||||
|
);
|
||||||
|
draw_3d_graph.add_node_edge(graph::node::END_MAIN_PASS, graph::node::TONEMAPPING);
|
||||||
draw_3d_graph.add_node_edge(
|
draw_3d_graph.add_node_edge(
|
||||||
graph::node::TONEMAPPING,
|
graph::node::TONEMAPPING,
|
||||||
graph::node::END_MAIN_PASS_POST_PROCESSING,
|
graph::node::END_MAIN_PASS_POST_PROCESSING,
|
||||||
|
|||||||
@ -45,7 +45,7 @@ impl Plugin for MsaaWritebackPlugin {
|
|||||||
);
|
);
|
||||||
core_3d.add_node_edge(
|
core_3d.add_node_edge(
|
||||||
crate::core_3d::graph::node::MSAA_WRITEBACK,
|
crate::core_3d::graph::node::MSAA_WRITEBACK,
|
||||||
crate::core_3d::graph::node::MAIN_PASS,
|
crate::core_3d::graph::node::START_MAIN_PASS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ impl Plugin for TemporalAntiAliasPlugin {
|
|||||||
draw_3d_graph.add_node(draw_3d_graph::node::TAA, taa_node);
|
draw_3d_graph.add_node(draw_3d_graph::node::TAA, taa_node);
|
||||||
// MAIN_PASS -> TAA -> BLOOM -> TONEMAPPING
|
// MAIN_PASS -> TAA -> BLOOM -> TONEMAPPING
|
||||||
draw_3d_graph.add_node_edge(
|
draw_3d_graph.add_node_edge(
|
||||||
crate::core_3d::graph::node::MAIN_PASS,
|
crate::core_3d::graph::node::END_MAIN_PASS,
|
||||||
draw_3d_graph::node::TAA,
|
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::BLOOM);
|
||||||
|
|||||||
@ -292,7 +292,7 @@ impl Plugin for PbrPlugin {
|
|||||||
draw_3d_graph.add_node(draw_3d_graph::node::SHADOW_PASS, shadow_pass_node);
|
draw_3d_graph.add_node(draw_3d_graph::node::SHADOW_PASS, shadow_pass_node);
|
||||||
draw_3d_graph.add_node_edge(
|
draw_3d_graph.add_node_edge(
|
||||||
draw_3d_graph::node::SHADOW_PASS,
|
draw_3d_graph::node::SHADOW_PASS,
|
||||||
bevy_core_pipeline::core_3d::graph::node::MAIN_PASS,
|
bevy_core_pipeline::core_3d::graph::node::START_MAIN_PASS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,7 +124,7 @@ pub fn build_ui_render(app: &mut App) {
|
|||||||
RunGraphOnViewNode::new(draw_ui_graph::NAME),
|
RunGraphOnViewNode::new(draw_ui_graph::NAME),
|
||||||
);
|
);
|
||||||
graph_3d.add_node_edge(
|
graph_3d.add_node_edge(
|
||||||
bevy_core_pipeline::core_3d::graph::node::MAIN_PASS,
|
bevy_core_pipeline::core_3d::graph::node::END_MAIN_PASS,
|
||||||
draw_ui_graph::node::UI_PASS,
|
draw_ui_graph::node::UI_PASS,
|
||||||
);
|
);
|
||||||
graph_3d.add_node_edge(
|
graph_3d.add_node_edge(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user