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:
parent
e072625264
commit
6ad93ede86
@ -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.
|
||||
///
|
||||
/// ```
|
||||
|
@ -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,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user