diff --git a/Cargo.toml b/Cargo.toml index aac8ea12e6f46..8068f9ed825ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -651,6 +651,13 @@ description = "Showcases wireframe rendering" category = "3D Rendering" wasm = true +[[example]] +name = "no_prepass" +path = "tests/3d/no_prepass.rs" + +[package.metadata.example.no_prepass] +hidden = true + # Animation [[example]] name = "animated_fox" diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index aea0f713a27cf..82a477c57039d 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1,6 +1,7 @@ use crate::{ render, AlphaMode, DrawMesh, DrawPrepass, EnvironmentMapLight, MeshPipeline, MeshPipelineKey, - MeshUniform, PrepassPlugin, RenderLightSystems, SetMeshBindGroup, SetMeshViewBindGroup, Shadow, + MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup, + SetMeshViewBindGroup, Shadow, }; use bevy_app::{App, IntoSystemAppConfig, Plugin}; use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle}; @@ -207,6 +208,9 @@ where .add_system(queue_material_meshes::.in_set(RenderSet::Queue)); } + // PrepassPipelinePlugin is required for shadow mapping and the optional PrepassPlugin + app.add_plugin(PrepassPipelinePlugin::::default()); + if self.prepass_enabled { app.add_plugin(PrepassPlugin::::default()); } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index acfb160dd35c8..407c357a230e4 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -59,15 +59,18 @@ pub const PREPASS_BINDINGS_SHADER_HANDLE: HandleUntyped = pub const PREPASS_UTILS_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4603948296044544); -pub struct PrepassPlugin(PhantomData); +/// Sets up everything required to use the prepass pipeline. +/// +/// This does not add the actual prepasses, see [`PrepassPlugin`] for that. +pub struct PrepassPipelinePlugin(PhantomData); -impl Default for PrepassPlugin { +impl Default for PrepassPipelinePlugin { fn default() -> Self { Self(Default::default()) } } -impl Plugin for PrepassPlugin +impl Plugin for PrepassPipelinePlugin where M::Data: PartialEq + Eq + Hash + Clone, { @@ -93,6 +96,34 @@ where Shader::from_wgsl ); + let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + render_app + .add_system(queue_prepass_view_bind_group::.in_set(RenderSet::Queue)) + .init_resource::>() + .init_resource::() + .init_resource::>>(); + } +} + +/// Sets up the prepasses for a [`Material`]. +/// +/// This depends on the [`PrepassPipelinePlugin`]. +pub struct PrepassPlugin(PhantomData); + +impl Default for PrepassPlugin { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Plugin for PrepassPlugin +where + M::Data: PartialEq + Eq + Hash + Clone, +{ + fn build(&self, app: &mut bevy_app::App) { let Ok(render_app) = app.get_sub_app_mut(RenderApp) else { return; }; @@ -104,15 +135,11 @@ where .in_set(RenderSet::Prepare) .after(bevy_render::view::prepare_windows), ) - .add_system(queue_prepass_view_bind_group::.in_set(RenderSet::Queue)) .add_system(queue_prepass_material_meshes::.in_set(RenderSet::Queue)) .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) - .init_resource::>() .init_resource::>() .init_resource::>() - .init_resource::() - .init_resource::>>() .add_render_command::>() .add_render_command::>(); } @@ -254,11 +281,12 @@ where let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?; - // The fragment shader is only used when the normal prepass is enabled or the material uses alpha cutoff values - let fragment = if key - .mesh_key - .intersects(MeshPipelineKey::NORMAL_PREPASS | MeshPipelineKey::ALPHA_MASK) - || blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA + // The fragment shader is only used when the normal prepass is enabled + // or the material uses alpha cutoff values and doesn't rely on the standard prepass shader + let fragment = if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) + || ((key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) + || blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA) + && self.material_fragment_shader.is_some()) { // Use the fragment shader from the material if present let frag_shader_handle = if let Some(handle) = &self.material_fragment_shader { diff --git a/tests/3d/no_prepass.rs b/tests/3d/no_prepass.rs new file mode 100644 index 0000000000000..589cfaa95caa2 --- /dev/null +++ b/tests/3d/no_prepass.rs @@ -0,0 +1,11 @@ +//! A test to confirm that `bevy` allows disabling the prepass of the standard material. +//! This is run in CI to ensure that this doesn't regress again. +use bevy::{pbr::PbrPlugin, prelude::*}; + +fn main() { + App::new() + .add_plugins(DefaultPlugins.set(PbrPlugin { + prepass_enabled: false, + })) + .run(); +}