Correctly disable prepass/shadows when configured on MaterialPlugin<M> (#19890)

Previously, the specialize/queue systems were added per-material and the
plugin prepass/shadow enable flags controlled whether we added those
systems. Now, we make this a property of the material instance and check
for it when specializing. Fixes
https://github.com/bevyengine/bevy/issues/19850.
This commit is contained in:
charlotte 🌸 2025-06-30 20:24:58 -07:00 committed by GitHub
parent e072625264
commit 6ad93ede86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 15 deletions

View File

@ -1,5 +1,3 @@
use core::ops::DerefMut;
use bevy_ecs::{
entity::{EntityHashMap, EntityHashSet},
prelude::*,
@ -19,6 +17,7 @@ use bevy_render::{
};
use bevy_transform::components::{GlobalTransform, Transform};
use bevy_utils::Parallel;
use core::{marker::PhantomData, ops::DerefMut};
use crate::*;
@ -91,6 +90,16 @@ pub mod light_consts {
}
}
/// Marker resource for whether shadows are enabled for this material type
#[derive(Resource, Debug)]
pub struct ShadowsEnabled<M: Material>(PhantomData<M>);
impl<M: Material> Default for ShadowsEnabled<M> {
fn default() -> Self {
Self(PhantomData)
}
}
/// Controls the resolution of [`PointLight`] shadow maps.
///
/// ```

View File

@ -372,6 +372,13 @@ where
}
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
if self.prepass_enabled {
render_app.init_resource::<PrepassEnabled<M>>();
}
if self.shadows_enabled {
render_app.init_resource::<ShadowsEnabled<M>>();
}
render_app
.add_systems(RenderStartup, setup_render_app::<M>)
.add_systems(
@ -1316,6 +1323,10 @@ pub struct MaterialProperties {
/// The key for this material, typically a bitfield of flags that are used to modify
/// the pipeline descriptor used for this material.
pub material_key: SmallVec<[u8; 8]>,
/// Whether shadows are enabled for this material
pub shadows_enabled: bool,
/// Whether prepass is enabled for this material
pub prepass_enabled: bool,
}
impl MaterialProperties {
@ -1394,7 +1405,11 @@ where
SRes<DrawFunctions<AlphaMask3dDeferred>>,
SRes<DrawFunctions<Shadow>>,
SRes<AssetServer>,
M::Param,
(
Option<SRes<ShadowsEnabled<M>>>,
Option<SRes<PrepassEnabled<M>>>,
M::Param,
),
);
fn prepare_asset(
@ -1415,10 +1430,14 @@ where
alpha_mask_deferred_draw_functions,
shadow_draw_functions,
asset_server,
material_param,
(shadows_enabled, prepass_enabled, material_param),
): &mut SystemParamItem<Self::Param>,
) -> Result<Self::ErasedAsset, PrepareAssetError<Self::SourceAsset>> {
let material_layout = M::bind_group_layout(render_device);
let shadows_enabled = shadows_enabled.is_some();
let prepass_enabled = prepass_enabled.is_some();
let draw_opaque_pbr = opaque_draw_functions.read().id::<DrawMaterial>();
let draw_alpha_mask_pbr = alpha_mask_draw_functions.read().id::<DrawMaterial>();
let draw_transmissive_pbr = transmissive_draw_functions.read().id::<DrawMaterial>();
@ -1584,6 +1603,8 @@ where
bindless,
specialize: Some(specialize::<M>),
material_key,
shadows_enabled,
prepass_enabled,
}),
})
}
@ -1621,6 +1642,8 @@ where
bindless,
specialize: Some(specialize::<M>),
material_key,
shadows_enabled,
prepass_enabled,
}),
})
}

View File

@ -4,11 +4,11 @@ use crate::{
alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout,
collect_meshes_for_gpu_building, set_mesh_motion_vector_flags, setup_morph_and_skinning_defs,
skin, DeferredDrawFunction, DeferredFragmentShader, DeferredVertexShader, DrawMesh,
EntitySpecializationTicks, ErasedMaterialPipelineKey, MaterialPipeline, MaterialProperties,
MeshLayouts, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial,
PrepassDrawFunction, PrepassFragmentShader, PrepassVertexShader, RenderLightmaps,
RenderMaterialInstances, RenderMeshInstanceFlags, RenderMeshInstances, RenderPhaseType,
SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
EntitySpecializationTicks, ErasedMaterialPipelineKey, Material, MaterialPipeline,
MaterialProperties, MeshLayouts, MeshPipeline, MeshPipelineKey, OpaqueRendererMethod,
PreparedMaterial, PrepassDrawFunction, PrepassFragmentShader, PrepassVertexShader,
RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags, RenderMeshInstances,
RenderPhaseType, SetMaterialBindGroup, SetMeshBindGroup, ShadowView,
};
use bevy_app::{App, Plugin, PreUpdate};
use bevy_render::{
@ -58,13 +58,15 @@ use crate::meshlet::{
use alloc::sync::Arc;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::component::Tick;
use bevy_ecs::system::SystemChangeTick;
use bevy_ecs::{component::Tick, system::SystemChangeTick};
use bevy_platform::collections::HashMap;
use bevy_render::erased_render_asset::ErasedRenderAssets;
use bevy_render::sync_world::MainEntityHashMap;
use bevy_render::view::RenderVisibleEntities;
use bevy_render::RenderSystems::{PrepareAssets, PrepareResources};
use bevy_render::{
erased_render_asset::ErasedRenderAssets,
sync_world::MainEntityHashMap,
view::RenderVisibleEntities,
RenderSystems::{PrepareAssets, PrepareResources},
};
use core::marker::PhantomData;
/// Sets up everything required to use the prepass pipeline.
///
@ -188,6 +190,16 @@ impl Plugin for PrepassPlugin {
}
}
/// Marker resource for whether prepass is enabled globally for this material type
#[derive(Resource, Debug)]
pub struct PrepassEnabled<M: Material>(PhantomData<M>);
impl<M: Material> Default for PrepassEnabled<M> {
fn default() -> Self {
PrepassEnabled(PhantomData)
}
}
#[derive(Resource)]
struct AnyPrepassPluginLoaded;
@ -911,6 +923,11 @@ pub fn specialize_prepass_material_meshes(
let Some(material) = render_materials.get(material_instance.asset_id) else {
continue;
};
if !material.properties.prepass_enabled && !material.properties.shadows_enabled {
// If the material was previously specialized for prepass, remove it
view_specialized_material_pipeline_cache.remove(visible_entity);
continue;
}
let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else {
continue;
};

View File

@ -1891,6 +1891,10 @@ pub fn specialize_shadows(
let Some(material) = render_materials.get(material_instance.asset_id) else {
continue;
};
if !material.properties.shadows_enabled {
// If the material is not a shadow caster, we don't need to specialize it.
continue;
}
if !mesh_instance
.flags
.contains(RenderMeshInstanceFlags::SHADOW_CASTER)