diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 967ccda522ace..0151654a9b05f 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1876,3 +1876,19 @@ pub fn get_mesh_instance_world_from_local( } } } + +pub(crate) trait MaterialPropertiesExt { + fn prepass_reads_material(&self) -> bool; +} + +impl MaterialPropertiesExt for MaterialProperties { + fn prepass_reads_material(&self) -> bool { + // The default prepass shaders doesn't need material's bind group, + // but for user provided prepass shaders currently we don't have a way to known this + // because material's bind group is used for both prepass and the other passes. + // + // So we have to disable the optimization for depth only prepass and always bind the material's bind group. + self.get_shader(PrepassVertexShader).is_some() + || self.get_shader(PrepassFragmentShader).is_some() + } +} diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 20644c2a2ac76..795c7ab331c49 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -4,11 +4,12 @@ use crate::{ alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout, collect_meshes_for_gpu_building, init_material_pipeline, set_mesh_motion_vector_flags, setup_morph_and_skinning_defs, skin, DeferredAlphaMaskDrawFunction, DeferredFragmentShader, - DeferredOpaqueDrawFunction, DeferredVertexShader, DrawMesh, MaterialPipeline, MeshLayouts, - MeshPipeline, MeshPipelineKey, PreparedMaterial, PrepassAlphaMaskDrawFunction, - PrepassFragmentShader, PrepassOpaqueDepthOnlyDrawFunction, PrepassOpaqueDrawFunction, - PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, RenderMeshInstanceFlags, - RenderMeshInstances, SetMaterialBindGroup, SetMeshBindGroup, ShadowView, + DeferredOpaqueDrawFunction, DeferredVertexShader, DrawMesh, MaterialPipeline, + MaterialPropertiesExt, MeshLayouts, MeshPipeline, MeshPipelineKey, PreparedMaterial, + PrepassAlphaMaskDrawFunction, PrepassFragmentShader, PrepassOpaqueDepthOnlyDrawFunction, + PrepassOpaqueDrawFunction, PrepassVertexShader, RenderLightmaps, RenderMaterialInstances, + RenderMeshInstanceFlags, RenderMeshInstances, SetMaterialBindGroup, SetMeshBindGroup, + ShadowView, }; use bevy_app::{App, Plugin, PreUpdate}; use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle}; @@ -390,7 +391,9 @@ impl SpecializedMeshPipeline for PrepassPipelineSpecializer { } fn is_depth_only_opaque_prepass(mesh_key: MeshPipelineKey) -> bool { - mesh_key.intersection(MeshPipelineKey::ALL_PREPASS_BITS) == MeshPipelineKey::DEPTH_PREPASS + !mesh_key.intersects(MeshPipelineKey::MAY_DISCARD | MeshPipelineKey::PREPASS_READS_MATERIAL) + && mesh_key.intersection(MeshPipelineKey::ALL_PREPASS_BITS) + == MeshPipelineKey::DEPTH_PREPASS } impl PrepassPipeline { @@ -425,7 +428,12 @@ impl PrepassPipeline { // or emulated by setting depth in the fragment shader for GPUs that don't support it natively. let emulate_unclipped_depth = mesh_key.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO) && !self.depth_clip_control_supported; - if is_depth_only_opaque_prepass(mesh_key) && !emulate_unclipped_depth { + if is_depth_only_opaque_prepass(mesh_key) + && !emulate_unclipped_depth + && !material_properties.prepass_reads_material() + { + // The shaders for depth only opaque prepass doesn't need material's bind group. + // We set an empty layout and batch them by setting `material_bind_group_index` to `None` in batch set key. bind_group_layouts.push(self.empty_layout.clone()); } else { bind_group_layouts.push( @@ -1181,6 +1189,10 @@ pub(crate) fn specialize_prepass_material_meshes( mesh_key |= MeshPipelineKey::VISIBILITY_RANGE_DITHER; } + if material.properties.prepass_reads_material() { + mesh_key |= MeshPipelineKey::PREPASS_READS_MATERIAL; + } + // If the previous frame has skins or morph targets, note that. if motion_vector_prepass.is_some() { if mesh_instance diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 0188614a17623..6bd5bf4376a4c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -2448,6 +2448,10 @@ pub(crate) fn specialize_shadows( _ => MeshPipelineKey::NONE, }; + if material.properties.prepass_reads_material() { + mesh_key |= MeshPipelineKey::PREPASS_READS_MATERIAL; + } + work_items.push(ShadowSpecializationWorkItem { visible_entity: *visible_entity, retained_view_entity: extracted_view_light.retained_view_entity,