Extract common RenderPhase code into render method (#7013)
# Objective All `RenderPhases` follow the same render procedure. The same code is duplicated multiple times across the codebase. ## Solution I simply extracted this code into a method on the `RenderPhase`. This avoids code duplication and makes setting up new `RenderPhases` easier. --- ## Changelog ### Changed You can now set up the rendering code of a `RenderPhase` directly using the `RenderPhase::render` method, instead of implementing it manually in your render graph node.
This commit is contained in:
parent
5566d73d9e
commit
ca85f6c903
@ -6,7 +6,7 @@ use bevy_ecs::prelude::*;
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
||||||
render_phase::{DrawFunctions, RenderPhase, TrackedRenderPass},
|
render_phase::RenderPhase,
|
||||||
render_resource::{LoadOp, Operations, RenderPassDescriptor},
|
render_resource::{LoadOp, Operations, RenderPassDescriptor},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ExtractedView, ViewTarget},
|
view::{ExtractedView, ViewTarget},
|
||||||
@ -77,21 +77,13 @@ impl Node for MainPass2dNode {
|
|||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<Transparent2d>>();
|
transparent_phase.render(
|
||||||
|
world,
|
||||||
let render_pass = render_context
|
render_context,
|
||||||
.command_encoder
|
view_entity,
|
||||||
.begin_render_pass(&pass_descriptor);
|
camera.viewport.as_ref(),
|
||||||
|
pass_descriptor,
|
||||||
let mut draw_functions = draw_functions.write();
|
);
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
for item in &transparent_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use bevy_ecs::prelude::*;
|
|||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
||||||
render_phase::{DrawFunctions, RenderPhase, TrackedRenderPass},
|
render_phase::RenderPhase,
|
||||||
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||||
@ -95,20 +95,13 @@ impl Node for MainPass3dNode {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<Opaque3d>>();
|
opaque_phase.render(
|
||||||
|
world,
|
||||||
let render_pass = render_context
|
render_context,
|
||||||
.command_encoder
|
view_entity,
|
||||||
.begin_render_pass(&pass_descriptor);
|
camera.viewport.as_ref(),
|
||||||
let mut draw_functions = draw_functions.write();
|
pass_descriptor,
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
);
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
for item in &opaque_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alpha_mask_phase.items.is_empty() {
|
if !alpha_mask_phase.items.is_empty() {
|
||||||
@ -134,20 +127,13 @@ impl Node for MainPass3dNode {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<AlphaMask3d>>();
|
alpha_mask_phase.render(
|
||||||
|
world,
|
||||||
let render_pass = render_context
|
render_context,
|
||||||
.command_encoder
|
view_entity,
|
||||||
.begin_render_pass(&pass_descriptor);
|
camera.viewport.as_ref(),
|
||||||
let mut draw_functions = draw_functions.write();
|
pass_descriptor,
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
);
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
for item in &alpha_mask_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !transparent_phase.items.is_empty() {
|
if !transparent_phase.items.is_empty() {
|
||||||
@ -178,20 +164,13 @@ impl Node for MainPass3dNode {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<Transparent3d>>();
|
transparent_phase.render(
|
||||||
|
world,
|
||||||
let render_pass = render_context
|
render_context,
|
||||||
.command_encoder
|
view_entity,
|
||||||
.begin_render_pass(&pass_descriptor);
|
camera.viewport.as_ref(),
|
||||||
let mut draw_functions = draw_functions.write();
|
pass_descriptor,
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
);
|
||||||
if let Some(viewport) = camera.viewport.as_ref() {
|
|
||||||
tracked_pass.set_camera_viewport(viewport);
|
|
||||||
}
|
|
||||||
for item in &transparent_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
|
||||||
|
|||||||
@ -1785,16 +1785,7 @@ impl Node for ShadowPassNode {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<Shadow>>();
|
shadow_phase.render(world, render_context, view_entity, None, pass_descriptor);
|
||||||
let render_pass = render_context
|
|
||||||
.command_encoder
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
let mut draw_functions = draw_functions.write();
|
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
for item in &shadow_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_light_entity, item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
mod draw;
|
mod draw;
|
||||||
mod draw_state;
|
mod draw_state;
|
||||||
|
|
||||||
|
use bevy_ecs::entity::Entity;
|
||||||
pub use draw::*;
|
pub use draw::*;
|
||||||
pub use draw_state::*;
|
pub use draw_state::*;
|
||||||
|
use wgpu::RenderPassDescriptor;
|
||||||
|
|
||||||
|
use crate::camera::Viewport;
|
||||||
|
use crate::renderer::RenderContext;
|
||||||
use bevy_ecs::prelude::{Component, Query};
|
use bevy_ecs::prelude::{Component, Query};
|
||||||
|
use bevy_ecs::world::World;
|
||||||
|
|
||||||
/// A resource to collect and sort draw requests for specific [`PhaseItems`](PhaseItem).
|
/// A resource to collect and sort draw requests for specific [`PhaseItems`](PhaseItem).
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -29,6 +34,32 @@ impl<I: PhaseItem> RenderPhase<I> {
|
|||||||
pub fn sort(&mut self) {
|
pub fn sort(&mut self) {
|
||||||
I::sort(&mut self.items);
|
I::sort(&mut self.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
&self,
|
||||||
|
world: &World,
|
||||||
|
render_context: &mut RenderContext,
|
||||||
|
view: Entity,
|
||||||
|
viewport: Option<&Viewport>,
|
||||||
|
pass_descriptor: RenderPassDescriptor,
|
||||||
|
) {
|
||||||
|
let render_pass = render_context
|
||||||
|
.command_encoder
|
||||||
|
.begin_render_pass(&pass_descriptor);
|
||||||
|
let mut render_pass = TrackedRenderPass::new(render_pass);
|
||||||
|
|
||||||
|
if let Some(viewport) = viewport {
|
||||||
|
render_pass.set_camera_viewport(viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw_functions = world.resource::<DrawFunctions<I>>();
|
||||||
|
let mut draw_functions = draw_functions.write();
|
||||||
|
|
||||||
|
for item in &self.items {
|
||||||
|
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap();
|
||||||
|
draw_function.draw(world, &mut render_pass, view, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: BatchedPhaseItem> RenderPhase<I> {
|
impl<I: BatchedPhaseItem> RenderPhase<I> {
|
||||||
|
|||||||
@ -85,18 +85,7 @@ impl Node for UiPassNode {
|
|||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let draw_functions = world.resource::<DrawFunctions<TransparentUi>>();
|
transparent_phase.render(world, render_context, view_entity, None, pass_descriptor);
|
||||||
|
|
||||||
let render_pass = render_context
|
|
||||||
.command_encoder
|
|
||||||
.begin_render_pass(&pass_descriptor);
|
|
||||||
|
|
||||||
let mut draw_functions = draw_functions.write();
|
|
||||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
|
||||||
for item in &transparent_phase.items {
|
|
||||||
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
|
|
||||||
draw_function.draw(world, &mut tracked_pass, view_entity, item);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user