Skip to content

Commit 9d18245

Browse files
geieredgarProfLander
authored andcommitted
Fix dependency of shadow mapping on the optional PrepassPlugin (bevyengine#7878)
# Objective Unfortunately, there are three issues with my changes introduced by bevyengine#7784. 1. The changes left some dead code. This is already taken care of here: bevyengine#7875. 2. Disabling prepass causes failures because the shadow mapping relies on the `PrepassPlugin` now. 3. Custom materials use the `prepass.wgsl` shader, but this does not always define a fragment entry point. This PR fixes 2. and 3. and resolves bevyengine#7879. ## Solution - Add a regression test with disabled prepass. - Split `PrepassPlugin` into two plugins: - `PrepassPipelinePlugin` contains the part that is required for the shadow mapping to work and is unconditionally added. - `PrepassPlugin` now only adds the systems and resources required for the "real" prepasses. - Add a noop fragment entry point to `prepass.wgsl`, used if `NORMAL_PASS` is not defined. Co-authored-by: Edgar Geier <[email protected]>
1 parent 2cca87d commit 9d18245

File tree

4 files changed

+63
-13
lines changed

4 files changed

+63
-13
lines changed

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,13 @@ description = "Showcases wireframe rendering"
651651
category = "3D Rendering"
652652
wasm = true
653653

654+
[[example]]
655+
name = "no_prepass"
656+
path = "tests/3d/no_prepass.rs"
657+
658+
[package.metadata.example.no_prepass]
659+
hidden = true
660+
654661
# Animation
655662
[[example]]
656663
name = "animated_fox"

crates/bevy_pbr/src/material.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
render, AlphaMode, DrawMesh, DrawPrepass, EnvironmentMapLight, MeshPipeline, MeshPipelineKey,
3-
MeshUniform, PrepassPlugin, RenderLightSystems, SetMeshBindGroup, SetMeshViewBindGroup, Shadow,
3+
MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup,
4+
SetMeshViewBindGroup, Shadow,
45
};
56
use bevy_app::{App, IntoSystemAppConfig, Plugin};
67
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
@@ -207,6 +208,9 @@ where
207208
.add_system(queue_material_meshes::<M>.in_set(RenderSet::Queue));
208209
}
209210

211+
// PrepassPipelinePlugin is required for shadow mapping and the optional PrepassPlugin
212+
app.add_plugin(PrepassPipelinePlugin::<M>::default());
213+
210214
if self.prepass_enabled {
211215
app.add_plugin(PrepassPlugin::<M>::default());
212216
}

crates/bevy_pbr/src/prepass/mod.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,18 @@ pub const PREPASS_BINDINGS_SHADER_HANDLE: HandleUntyped =
5959
pub const PREPASS_UTILS_SHADER_HANDLE: HandleUntyped =
6060
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4603948296044544);
6161

62-
pub struct PrepassPlugin<M: Material>(PhantomData<M>);
62+
/// Sets up everything required to use the prepass pipeline.
63+
///
64+
/// This does not add the actual prepasses, see [`PrepassPlugin`] for that.
65+
pub struct PrepassPipelinePlugin<M: Material>(PhantomData<M>);
6366

64-
impl<M: Material> Default for PrepassPlugin<M> {
67+
impl<M: Material> Default for PrepassPipelinePlugin<M> {
6568
fn default() -> Self {
6669
Self(Default::default())
6770
}
6871
}
6972

70-
impl<M: Material> Plugin for PrepassPlugin<M>
73+
impl<M: Material> Plugin for PrepassPipelinePlugin<M>
7174
where
7275
M::Data: PartialEq + Eq + Hash + Clone,
7376
{
@@ -93,6 +96,34 @@ where
9396
Shader::from_wgsl
9497
);
9598

99+
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
100+
return;
101+
};
102+
103+
render_app
104+
.add_system(queue_prepass_view_bind_group::<M>.in_set(RenderSet::Queue))
105+
.init_resource::<PrepassPipeline<M>>()
106+
.init_resource::<PrepassViewBindGroup>()
107+
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>();
108+
}
109+
}
110+
111+
/// Sets up the prepasses for a [`Material`].
112+
///
113+
/// This depends on the [`PrepassPipelinePlugin`].
114+
pub struct PrepassPlugin<M: Material>(PhantomData<M>);
115+
116+
impl<M: Material> Default for PrepassPlugin<M> {
117+
fn default() -> Self {
118+
Self(Default::default())
119+
}
120+
}
121+
122+
impl<M: Material> Plugin for PrepassPlugin<M>
123+
where
124+
M::Data: PartialEq + Eq + Hash + Clone,
125+
{
126+
fn build(&self, app: &mut bevy_app::App) {
96127
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
97128
return;
98129
};
@@ -104,15 +135,11 @@ where
104135
.in_set(RenderSet::Prepare)
105136
.after(bevy_render::view::prepare_windows),
106137
)
107-
.add_system(queue_prepass_view_bind_group::<M>.in_set(RenderSet::Queue))
108138
.add_system(queue_prepass_material_meshes::<M>.in_set(RenderSet::Queue))
109139
.add_system(sort_phase_system::<Opaque3dPrepass>.in_set(RenderSet::PhaseSort))
110140
.add_system(sort_phase_system::<AlphaMask3dPrepass>.in_set(RenderSet::PhaseSort))
111-
.init_resource::<PrepassPipeline<M>>()
112141
.init_resource::<DrawFunctions<Opaque3dPrepass>>()
113142
.init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
114-
.init_resource::<PrepassViewBindGroup>()
115-
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>()
116143
.add_render_command::<Opaque3dPrepass, DrawPrepass<M>>()
117144
.add_render_command::<AlphaMask3dPrepass, DrawPrepass<M>>();
118145
}
@@ -254,11 +281,12 @@ where
254281

255282
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
256283

257-
// The fragment shader is only used when the normal prepass is enabled or the material uses alpha cutoff values
258-
let fragment = if key
259-
.mesh_key
260-
.intersects(MeshPipelineKey::NORMAL_PREPASS | MeshPipelineKey::ALPHA_MASK)
261-
|| blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA
284+
// The fragment shader is only used when the normal prepass is enabled
285+
// or the material uses alpha cutoff values and doesn't rely on the standard prepass shader
286+
let fragment = if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS)
287+
|| ((key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK)
288+
|| blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA)
289+
&& self.material_fragment_shader.is_some())
262290
{
263291
// Use the fragment shader from the material if present
264292
let frag_shader_handle = if let Some(handle) = &self.material_fragment_shader {

tests/3d/no_prepass.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! A test to confirm that `bevy` allows disabling the prepass of the standard material.
2+
//! This is run in CI to ensure that this doesn't regress again.
3+
use bevy::{pbr::PbrPlugin, prelude::*};
4+
5+
fn main() {
6+
App::new()
7+
.add_plugins(DefaultPlugins.set(PbrPlugin {
8+
prepass_enabled: false,
9+
}))
10+
.run();
11+
}

0 commit comments

Comments
 (0)