Implement occlusion culling for the deferred rendering pipeline. (#17934)
Deferred rendering currently doesn't support occlusion culling. This PR implements it in a straightforward way, mirroring what we already do for the non-deferred pipeline. On the rend3 sci-fi base test scene, this resulted in roughly a 2× speedup when applied on top of my other patches. For that scene, it was useful to add another option, `--add-light`, which forces the addition of a shadow-casting light, to the scene viewer, which I included in this patch.
This commit is contained in:
parent
f15437e4dc
commit
8de6b16e9d
@ -19,7 +19,8 @@ pub mod graph {
|
|||||||
EarlyPrepass,
|
EarlyPrepass,
|
||||||
EarlyDownsampleDepth,
|
EarlyDownsampleDepth,
|
||||||
LatePrepass,
|
LatePrepass,
|
||||||
DeferredPrepass,
|
EarlyDeferredPrepass,
|
||||||
|
LateDeferredPrepass,
|
||||||
CopyDeferredLightingId,
|
CopyDeferredLightingId,
|
||||||
EndPrepasses,
|
EndPrepasses,
|
||||||
StartMainPass,
|
StartMainPass,
|
||||||
@ -112,7 +113,8 @@ use tracing::warn;
|
|||||||
use crate::{
|
use crate::{
|
||||||
core_3d::main_transmissive_pass_3d_node::MainTransmissivePass3dNode,
|
core_3d::main_transmissive_pass_3d_node::MainTransmissivePass3dNode,
|
||||||
deferred::{
|
deferred::{
|
||||||
copy_lighting_id::CopyDeferredLightingIdNode, node::DeferredGBufferPrepassNode,
|
copy_lighting_id::CopyDeferredLightingIdNode,
|
||||||
|
node::{EarlyDeferredGBufferPrepassNode, LateDeferredGBufferPrepassNode},
|
||||||
AlphaMask3dDeferred, Opaque3dDeferred, DEFERRED_LIGHTING_PASS_ID_FORMAT,
|
AlphaMask3dDeferred, Opaque3dDeferred, DEFERRED_LIGHTING_PASS_ID_FORMAT,
|
||||||
DEFERRED_PREPASS_FORMAT,
|
DEFERRED_PREPASS_FORMAT,
|
||||||
},
|
},
|
||||||
@ -179,9 +181,13 @@ impl Plugin for Core3dPlugin {
|
|||||||
.add_render_sub_graph(Core3d)
|
.add_render_sub_graph(Core3d)
|
||||||
.add_render_graph_node::<ViewNodeRunner<EarlyPrepassNode>>(Core3d, Node3d::EarlyPrepass)
|
.add_render_graph_node::<ViewNodeRunner<EarlyPrepassNode>>(Core3d, Node3d::EarlyPrepass)
|
||||||
.add_render_graph_node::<ViewNodeRunner<LatePrepassNode>>(Core3d, Node3d::LatePrepass)
|
.add_render_graph_node::<ViewNodeRunner<LatePrepassNode>>(Core3d, Node3d::LatePrepass)
|
||||||
.add_render_graph_node::<ViewNodeRunner<DeferredGBufferPrepassNode>>(
|
.add_render_graph_node::<ViewNodeRunner<EarlyDeferredGBufferPrepassNode>>(
|
||||||
Core3d,
|
Core3d,
|
||||||
Node3d::DeferredPrepass,
|
Node3d::EarlyDeferredPrepass,
|
||||||
|
)
|
||||||
|
.add_render_graph_node::<ViewNodeRunner<LateDeferredGBufferPrepassNode>>(
|
||||||
|
Core3d,
|
||||||
|
Node3d::LateDeferredPrepass,
|
||||||
)
|
)
|
||||||
.add_render_graph_node::<ViewNodeRunner<CopyDeferredLightingIdNode>>(
|
.add_render_graph_node::<ViewNodeRunner<CopyDeferredLightingIdNode>>(
|
||||||
Core3d,
|
Core3d,
|
||||||
@ -210,8 +216,9 @@ impl Plugin for Core3dPlugin {
|
|||||||
Core3d,
|
Core3d,
|
||||||
(
|
(
|
||||||
Node3d::EarlyPrepass,
|
Node3d::EarlyPrepass,
|
||||||
|
Node3d::EarlyDeferredPrepass,
|
||||||
Node3d::LatePrepass,
|
Node3d::LatePrepass,
|
||||||
Node3d::DeferredPrepass,
|
Node3d::LateDeferredPrepass,
|
||||||
Node3d::CopyDeferredLightingId,
|
Node3d::CopyDeferredLightingId,
|
||||||
Node3d::EndPrepasses,
|
Node3d::EndPrepasses,
|
||||||
Node3d::StartMainPass,
|
Node3d::StartMainPass,
|
||||||
@ -943,7 +950,6 @@ fn configure_occlusion_culling_view_targets(
|
|||||||
With<OcclusionCulling>,
|
With<OcclusionCulling>,
|
||||||
Without<NoIndirectDrawing>,
|
Without<NoIndirectDrawing>,
|
||||||
With<DepthPrepass>,
|
With<DepthPrepass>,
|
||||||
Without<DeferredPrepass>,
|
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||||
|
use bevy_render::experimental::occlusion_culling::OcclusionCulling;
|
||||||
use bevy_render::render_graph::ViewNode;
|
use bevy_render::render_graph::ViewNode;
|
||||||
|
|
||||||
use bevy_render::view::ExtractedView;
|
use bevy_render::view::{ExtractedView, NoIndirectDrawing};
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::ExtractedCamera,
|
camera::ExtractedCamera,
|
||||||
render_graph::{NodeRunError, RenderGraphContext},
|
render_graph::{NodeRunError, RenderGraphContext},
|
||||||
@ -18,30 +19,100 @@ use crate::prepass::ViewPrepassTextures;
|
|||||||
|
|
||||||
use super::{AlphaMask3dDeferred, Opaque3dDeferred};
|
use super::{AlphaMask3dDeferred, Opaque3dDeferred};
|
||||||
|
|
||||||
/// Render node used by the prepass.
|
/// The phase of the deferred prepass that draws meshes that were visible last
|
||||||
|
/// frame.
|
||||||
///
|
///
|
||||||
/// By default, inserted before the main pass in the render graph.
|
/// If occlusion culling isn't in use, this prepass simply draws all meshes.
|
||||||
|
///
|
||||||
|
/// Like all prepass nodes, this is inserted before the main pass in the render
|
||||||
|
/// graph.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DeferredGBufferPrepassNode;
|
pub struct EarlyDeferredGBufferPrepassNode;
|
||||||
|
|
||||||
impl ViewNode for DeferredGBufferPrepassNode {
|
impl ViewNode for EarlyDeferredGBufferPrepassNode {
|
||||||
|
type ViewQuery = <LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery;
|
||||||
|
|
||||||
|
fn run<'w>(
|
||||||
|
&self,
|
||||||
|
graph: &mut RenderGraphContext,
|
||||||
|
render_context: &mut RenderContext<'w>,
|
||||||
|
view_query: QueryItem<'w, Self::ViewQuery>,
|
||||||
|
world: &'w World,
|
||||||
|
) -> Result<(), NodeRunError> {
|
||||||
|
run_deferred_prepass(
|
||||||
|
graph,
|
||||||
|
render_context,
|
||||||
|
view_query,
|
||||||
|
false,
|
||||||
|
world,
|
||||||
|
"early deferred prepass",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The phase of the prepass that runs after occlusion culling against the
|
||||||
|
/// meshes that were visible last frame.
|
||||||
|
///
|
||||||
|
/// If occlusion culling isn't in use, this is a no-op.
|
||||||
|
///
|
||||||
|
/// Like all prepass nodes, this is inserted before the main pass in the render
|
||||||
|
/// graph.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LateDeferredGBufferPrepassNode;
|
||||||
|
|
||||||
|
impl ViewNode for LateDeferredGBufferPrepassNode {
|
||||||
type ViewQuery = (
|
type ViewQuery = (
|
||||||
&'static ExtractedCamera,
|
&'static ExtractedCamera,
|
||||||
&'static ExtractedView,
|
&'static ExtractedView,
|
||||||
&'static ViewDepthTexture,
|
&'static ViewDepthTexture,
|
||||||
&'static ViewPrepassTextures,
|
&'static ViewPrepassTextures,
|
||||||
|
Has<OcclusionCulling>,
|
||||||
|
Has<NoIndirectDrawing>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run<'w>(
|
fn run<'w>(
|
||||||
&self,
|
&self,
|
||||||
graph: &mut RenderGraphContext,
|
graph: &mut RenderGraphContext,
|
||||||
render_context: &mut RenderContext<'w>,
|
render_context: &mut RenderContext<'w>,
|
||||||
(camera, extracted_view, view_depth_texture, view_prepass_textures): QueryItem<
|
view_query: QueryItem<'w, Self::ViewQuery>,
|
||||||
'w,
|
|
||||||
Self::ViewQuery,
|
|
||||||
>,
|
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
|
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
|
||||||
|
if !occlusion_culling || no_indirect_drawing {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
run_deferred_prepass(
|
||||||
|
graph,
|
||||||
|
render_context,
|
||||||
|
view_query,
|
||||||
|
true,
|
||||||
|
world,
|
||||||
|
"late deferred prepass",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the deferred prepass that draws all meshes to the depth buffer and
|
||||||
|
/// G-buffers.
|
||||||
|
///
|
||||||
|
/// If occlusion culling isn't in use, and a prepass is enabled, then there's
|
||||||
|
/// only one prepass. If occlusion culling is in use, then any prepass is split
|
||||||
|
/// into two: an *early* prepass and a *late* prepass. The early prepass draws
|
||||||
|
/// what was visible last frame, and the last prepass performs occlusion culling
|
||||||
|
/// against a conservative hierarchical Z buffer before drawing unoccluded
|
||||||
|
/// meshes.
|
||||||
|
fn run_deferred_prepass<'w>(
|
||||||
|
graph: &mut RenderGraphContext,
|
||||||
|
render_context: &mut RenderContext<'w>,
|
||||||
|
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
|
||||||
|
'w,
|
||||||
|
<LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
|
||||||
|
>,
|
||||||
|
is_late: bool,
|
||||||
|
world: &'w World,
|
||||||
|
label: &'static str,
|
||||||
|
) -> Result<(), NodeRunError> {
|
||||||
let (Some(opaque_deferred_phases), Some(alpha_mask_deferred_phases)) = (
|
let (Some(opaque_deferred_phases), Some(alpha_mask_deferred_phases)) = (
|
||||||
world.get_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>(),
|
world.get_resource::<ViewBinnedRenderPhases<Opaque3dDeferred>>(),
|
||||||
world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>(),
|
world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dDeferred>>(),
|
||||||
@ -76,18 +147,23 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
// Appears to be unsupported: https://registry.khronos.org/webgl/specs/latest/2.0/#3.7.9
|
// Appears to be unsupported: https://registry.khronos.org/webgl/specs/latest/2.0/#3.7.9
|
||||||
// For webgl2 we fallback to manually clearing
|
// For webgl2 we fallback to manually clearing
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
||||||
|
if !is_late {
|
||||||
if let Some(deferred_texture) = &view_prepass_textures.deferred {
|
if let Some(deferred_texture) = &view_prepass_textures.deferred {
|
||||||
render_context.command_encoder().clear_texture(
|
render_context.command_encoder().clear_texture(
|
||||||
&deferred_texture.texture.texture,
|
&deferred_texture.texture.texture,
|
||||||
&bevy_render::render_resource::ImageSubresourceRange::default(),
|
&bevy_render::render_resource::ImageSubresourceRange::default(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
color_attachments.push(
|
color_attachments.push(
|
||||||
view_prepass_textures
|
view_prepass_textures
|
||||||
.deferred
|
.deferred
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|deferred_texture| {
|
.map(|deferred_texture| {
|
||||||
|
if is_late {
|
||||||
|
deferred_texture.get_attachment()
|
||||||
|
} else {
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
||||||
{
|
{
|
||||||
bevy_render::render_resource::RenderPassColorAttachment {
|
bevy_render::render_resource::RenderPassColorAttachment {
|
||||||
@ -105,6 +181,7 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
feature = "webgpu"
|
feature = "webgpu"
|
||||||
))]
|
))]
|
||||||
deferred_texture.get_attachment()
|
deferred_texture.get_attachment()
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -128,14 +205,13 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
let _deferred_span = info_span!("deferred_prepass").entered();
|
let _deferred_span = info_span!("deferred_prepass").entered();
|
||||||
|
|
||||||
// Command encoder setup
|
// Command encoder setup
|
||||||
let mut command_encoder =
|
let mut command_encoder = render_device.create_command_encoder(&CommandEncoderDescriptor {
|
||||||
render_device.create_command_encoder(&CommandEncoderDescriptor {
|
|
||||||
label: Some("deferred_prepass_command_encoder"),
|
label: Some("deferred_prepass_command_encoder"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Render pass setup
|
// Render pass setup
|
||||||
let render_pass = command_encoder.begin_render_pass(&RenderPassDescriptor {
|
let render_pass = command_encoder.begin_render_pass(&RenderPassDescriptor {
|
||||||
label: Some("deferred_prepass"),
|
label: Some(label),
|
||||||
color_attachments: &color_attachments,
|
color_attachments: &color_attachments,
|
||||||
depth_stencil_attachment,
|
depth_stencil_attachment,
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
@ -153,8 +229,7 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
{
|
{
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
|
let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
|
||||||
if let Err(err) = opaque_deferred_phase.render(&mut render_pass, world, view_entity)
|
if let Err(err) = opaque_deferred_phase.render(&mut render_pass, world, view_entity) {
|
||||||
{
|
|
||||||
error!("Error encountered while rendering the opaque deferred phase {err:?}");
|
error!("Error encountered while rendering the opaque deferred phase {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,12 +238,9 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
if !alpha_mask_deferred_phase.is_empty() {
|
if !alpha_mask_deferred_phase.is_empty() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
|
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
|
||||||
if let Err(err) =
|
if let Err(err) = alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity)
|
||||||
alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity)
|
|
||||||
{
|
{
|
||||||
error!(
|
error!("Error encountered while rendering the alpha mask deferred phase {err:?}");
|
||||||
"Error encountered while rendering the alpha mask deferred phase {err:?}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,5 +259,4 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ use crate::{
|
|||||||
graph::{Core3d, Node3d},
|
graph::{Core3d, Node3d},
|
||||||
prepare_core_3d_depth_textures,
|
prepare_core_3d_depth_textures,
|
||||||
},
|
},
|
||||||
prepass::{DeferredPrepass, DepthPrepass},
|
prepass::DepthPrepass,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Identifies the `downsample_depth.wgsl` shader.
|
/// Identifies the `downsample_depth.wgsl` shader.
|
||||||
@ -93,9 +93,10 @@ impl Plugin for MipGenerationPlugin {
|
|||||||
Core3d,
|
Core3d,
|
||||||
(
|
(
|
||||||
Node3d::EarlyPrepass,
|
Node3d::EarlyPrepass,
|
||||||
|
Node3d::EarlyDeferredPrepass,
|
||||||
Node3d::EarlyDownsampleDepth,
|
Node3d::EarlyDownsampleDepth,
|
||||||
Node3d::LatePrepass,
|
Node3d::LatePrepass,
|
||||||
Node3d::DeferredPrepass,
|
Node3d::LateDeferredPrepass,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.add_render_graph_edges(
|
.add_render_graph_edges(
|
||||||
@ -651,7 +652,6 @@ fn prepare_view_depth_pyramids(
|
|||||||
With<OcclusionCulling>,
|
With<OcclusionCulling>,
|
||||||
Without<NoIndirectDrawing>,
|
Without<NoIndirectDrawing>,
|
||||||
With<DepthPrepass>,
|
With<DepthPrepass>,
|
||||||
Without<DeferredPrepass>,
|
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
|
@ -66,6 +66,7 @@ impl ViewNode for LatePrepassNode {
|
|||||||
Option<&'static PreviousViewUniformOffset>,
|
Option<&'static PreviousViewUniformOffset>,
|
||||||
Has<OcclusionCulling>,
|
Has<OcclusionCulling>,
|
||||||
Has<NoIndirectDrawing>,
|
Has<NoIndirectDrawing>,
|
||||||
|
Has<DeferredPrepass>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run<'w>(
|
fn run<'w>(
|
||||||
@ -77,7 +78,7 @@ impl ViewNode for LatePrepassNode {
|
|||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
// We only need a late prepass if we have occlusion culling and indirect
|
// We only need a late prepass if we have occlusion culling and indirect
|
||||||
// drawing.
|
// drawing.
|
||||||
let (_, _, _, _, _, _, _, _, _, occlusion_culling, no_indirect_drawing) = query;
|
let (_, _, _, _, _, _, _, _, _, occlusion_culling, no_indirect_drawing, _) = query;
|
||||||
if !occlusion_culling || no_indirect_drawing {
|
if !occlusion_culling || no_indirect_drawing {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -110,10 +111,18 @@ fn run_prepass<'w>(
|
|||||||
view_prev_uniform_offset,
|
view_prev_uniform_offset,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
|
has_deferred,
|
||||||
): QueryItem<'w, <LatePrepassNode as ViewNode>::ViewQuery>,
|
): QueryItem<'w, <LatePrepassNode as ViewNode>::ViewQuery>,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
label: &'static str,
|
label: &'static str,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
|
// If we're using deferred rendering, there will be a deferred prepass
|
||||||
|
// instead of this one. Just bail out so we don't have to bother looking at
|
||||||
|
// the empty bins.
|
||||||
|
if has_deferred {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let (Some(opaque_prepass_phases), Some(alpha_mask_prepass_phases)) = (
|
let (Some(opaque_prepass_phases), Some(alpha_mask_prepass_phases)) = (
|
||||||
world.get_resource::<ViewBinnedRenderPhases<Opaque3dPrepass>>(),
|
world.get_resource::<ViewBinnedRenderPhases<Opaque3dPrepass>>(),
|
||||||
world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dPrepass>>(),
|
world.get_resource::<ViewBinnedRenderPhases<AlphaMask3dPrepass>>(),
|
||||||
|
@ -258,8 +258,6 @@ impl Plugin for MeshletPlugin {
|
|||||||
NodeMeshlet::Prepass,
|
NodeMeshlet::Prepass,
|
||||||
//
|
//
|
||||||
NodeMeshlet::DeferredPrepass,
|
NodeMeshlet::DeferredPrepass,
|
||||||
Node3d::DeferredPrepass,
|
|
||||||
Node3d::CopyDeferredLightingId,
|
|
||||||
Node3d::EndPrepasses,
|
Node3d::EndPrepasses,
|
||||||
//
|
//
|
||||||
Node3d::StartMainPass,
|
Node3d::StartMainPass,
|
||||||
|
@ -13,10 +13,7 @@ use bevy_asset::{load_internal_asset, weak_handle, Handle};
|
|||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_3d::graph::{Core3d, Node3d},
|
core_3d::graph::{Core3d, Node3d},
|
||||||
experimental::mip_generation::ViewDepthPyramid,
|
experimental::mip_generation::ViewDepthPyramid,
|
||||||
prepass::{
|
prepass::{DepthPrepass, PreviousViewData, PreviousViewUniformOffset, PreviousViewUniforms},
|
||||||
DeferredPrepass, DepthPrepass, PreviousViewData, PreviousViewUniformOffset,
|
|
||||||
PreviousViewUniforms,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
@ -140,7 +137,6 @@ pub struct LateGpuPreprocessNode {
|
|||||||
Without<NoIndirectDrawing>,
|
Without<NoIndirectDrawing>,
|
||||||
With<OcclusionCulling>,
|
With<OcclusionCulling>,
|
||||||
With<DepthPrepass>,
|
With<DepthPrepass>,
|
||||||
Without<DeferredPrepass>,
|
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
@ -159,7 +155,6 @@ pub struct EarlyPrepassBuildIndirectParametersNode {
|
|||||||
Without<SkipGpuPreprocess>,
|
Without<SkipGpuPreprocess>,
|
||||||
Without<NoIndirectDrawing>,
|
Without<NoIndirectDrawing>,
|
||||||
With<DepthPrepass>,
|
With<DepthPrepass>,
|
||||||
Without<DeferredPrepass>,
|
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
@ -180,7 +175,6 @@ pub struct LatePrepassBuildIndirectParametersNode {
|
|||||||
Without<NoIndirectDrawing>,
|
Without<NoIndirectDrawing>,
|
||||||
With<DepthPrepass>,
|
With<DepthPrepass>,
|
||||||
With<OcclusionCulling>,
|
With<OcclusionCulling>,
|
||||||
Without<DeferredPrepass>,
|
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
@ -527,21 +521,18 @@ impl Plugin for GpuMeshPreprocessPlugin {
|
|||||||
NodePbr::EarlyGpuPreprocess,
|
NodePbr::EarlyGpuPreprocess,
|
||||||
NodePbr::EarlyPrepassBuildIndirectParameters,
|
NodePbr::EarlyPrepassBuildIndirectParameters,
|
||||||
Node3d::EarlyPrepass,
|
Node3d::EarlyPrepass,
|
||||||
|
Node3d::EarlyDeferredPrepass,
|
||||||
Node3d::EarlyDownsampleDepth,
|
Node3d::EarlyDownsampleDepth,
|
||||||
NodePbr::LateGpuPreprocess,
|
NodePbr::LateGpuPreprocess,
|
||||||
NodePbr::LatePrepassBuildIndirectParameters,
|
NodePbr::LatePrepassBuildIndirectParameters,
|
||||||
Node3d::LatePrepass,
|
Node3d::LatePrepass,
|
||||||
|
Node3d::LateDeferredPrepass,
|
||||||
NodePbr::MainBuildIndirectParameters,
|
NodePbr::MainBuildIndirectParameters,
|
||||||
// Shadows don't currently support occlusion culling, so we
|
// Shadows don't currently support occlusion culling, so we
|
||||||
// treat shadows as effectively the main phase for our
|
// treat shadows as effectively the main phase for our
|
||||||
// purposes.
|
// purposes.
|
||||||
NodePbr::ShadowPass,
|
NodePbr::ShadowPass,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
.add_render_graph_edge(
|
|
||||||
Core3d,
|
|
||||||
NodePbr::MainBuildIndirectParameters,
|
|
||||||
Node3d::DeferredPrepass,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ struct Args {
|
|||||||
/// enable deferred shading
|
/// enable deferred shading
|
||||||
#[argh(switch)]
|
#[argh(switch)]
|
||||||
deferred: Option<bool>,
|
deferred: Option<bool>,
|
||||||
|
/// spawn a light even if the scene already has one
|
||||||
|
#[argh(switch)]
|
||||||
|
add_light: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -204,7 +207,7 @@ fn setup_scene_after_load(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Spawn a default light if the scene does not have one
|
// Spawn a default light if the scene does not have one
|
||||||
if !scene_handle.has_light {
|
if !scene_handle.has_light || args.add_light == Some(true) {
|
||||||
info!("Spawning a directional light");
|
info!("Spawning a directional light");
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
DirectionalLight::default(),
|
DirectionalLight::default(),
|
||||||
|
Loading…
Reference in New Issue
Block a user