diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 19c5349df3119..e9dbce227edfc 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -472,6 +472,9 @@ pub fn queue_material_meshes( AlphaMode::Multiply => { mesh_key |= MeshPipelineKey::BLEND_MULTIPLY; } + AlphaMode::Mask(_) => { + mesh_key |= MeshPipelineKey::MAY_DISCARD; + } _ => (), } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 7fd87d4716f6c..9307bc0d75aa9 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -364,8 +364,8 @@ where shader_defs.push("DEPTH_PREPASS".into()); } - if key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) { - shader_defs.push("ALPHA_MASK".into()); + if key.mesh_key.contains(MeshPipelineKey::MAY_DISCARD) { + shader_defs.push("MAY_DISCARD".into()); } let blend_key = key @@ -467,9 +467,7 @@ where // is enabled or the material uses alpha cutoff values and doesn't rely on the standard // prepass shader let fragment_required = !targets.is_empty() - || ((key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) - || blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA - || blend_key == MeshPipelineKey::BLEND_ALPHA) + || (key.mesh_key.contains(MeshPipelineKey::MAY_DISCARD) && self.material_fragment_shader.is_some()); let fragment = fragment_required.then(|| { @@ -967,7 +965,7 @@ pub fn queue_prepass_material_meshes( let alpha_mode = material.properties.alpha_mode; match alpha_mode { AlphaMode::Opaque => {} - AlphaMode::Mask(_) => mesh_key |= MeshPipelineKey::ALPHA_MASK, + AlphaMode::Mask(_) => mesh_key |= MeshPipelineKey::MAY_DISCARD, AlphaMode::Blend | AlphaMode::Premultiplied | AlphaMode::Add diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 410ec24471b7a..85dacdad9be35 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1608,11 +1608,11 @@ pub fn queue_shadows( } let alpha_mode = material.properties.alpha_mode; match alpha_mode { - AlphaMode::Mask(_) => { - mesh_key |= MeshPipelineKey::ALPHA_MASK; - } - AlphaMode::Blend | AlphaMode::Premultiplied | AlphaMode::Add => { - mesh_key |= MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA; + AlphaMode::Mask(_) + | AlphaMode::Blend + | AlphaMode::Premultiplied + | AlphaMode::Add => { + mesh_key |= MeshPipelineKey::MAY_DISCARD; } _ => {} } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 3224c1275ea5e..3a3834a8133a9 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -582,7 +582,8 @@ bitflags::bitflags! { const DEPTH_PREPASS = (1 << 3); const NORMAL_PREPASS = (1 << 4); const MOTION_VECTOR_PREPASS = (1 << 5); - const ALPHA_MASK = (1 << 6); + const MAY_DISCARD = (1 << 6); // Guards shader codepaths that may discard, allowing early depth tests in most cases + // See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test const ENVIRONMENT_MAP = (1 << 7); const DEPTH_CLAMP_ORTHO = (1 << 8); const BLEND_RESERVED_BITS = Self::BLEND_MASK_BITS << Self::BLEND_SHIFT_BITS; // ← Bitmask reserving bits for the blend state @@ -795,6 +796,10 @@ impl SpecializedMeshPipeline for MeshPipeline { } } + if key.contains(MeshPipelineKey::MAY_DISCARD) { + shader_defs.push("MAY_DISCARD".into()); + } + if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) { shader_defs.push("ENVIRONMENT_MAP".into()); } diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 1bc782fc19f3d..56e3d177731cb 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -14,16 +14,20 @@ fn alpha_discard(material: StandardMaterial, output_color: vec4) -> vec4= material.alpha_cutoff { // NOTE: If rendering as masked alpha and >= the cutoff, render as fully opaque color.a = 1.0; } else { - // NOTE: output_color.a < in.material.alpha_cutoff should not is not rendered - // NOTE: This and any other discards mean that early-z testing cannot be done! + // NOTE: output_color.a < in.material.alpha_cutoff should not be rendered discard; } } +#endif + return color; } diff --git a/crates/bevy_pbr/src/render/pbr_prepass.wgsl b/crates/bevy_pbr/src/render/pbr_prepass.wgsl index d96a23b845d4b..1a90c4570934f 100644 --- a/crates/bevy_pbr/src/render/pbr_prepass.wgsl +++ b/crates/bevy_pbr/src/render/pbr_prepass.wgsl @@ -30,19 +30,7 @@ const PREMULTIPLIED_ALPHA_CUTOFF = 0.05; // We can use a simplified version of alpha_discard() here since we only need to handle the alpha_cutoff fn prepass_alpha_discard(in: FragmentInput) { -// This is a workaround since the preprocessor does not support -// #if defined(ALPHA_MASK) || defined(BLEND_PREMULTIPLIED_ALPHA) -#ifndef ALPHA_MASK -#ifndef BLEND_PREMULTIPLIED_ALPHA -#ifndef BLEND_ALPHA - -#define EMPTY_PREPASS_ALPHA_DISCARD - -#endif // BLEND_ALPHA -#endif // BLEND_PREMULTIPLIED_ALPHA not defined -#endif // ALPHA_MASK not defined - -#ifndef EMPTY_PREPASS_ALPHA_DISCARD +#ifdef MAY_DISCARD var output_color: vec4 = material.base_color; #ifdef VERTEX_UVS @@ -51,22 +39,22 @@ fn prepass_alpha_discard(in: FragmentInput) { } #endif // VERTEX_UVS -#ifdef ALPHA_MASK - if ((material.flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK) != 0u) && output_color.a < material.alpha_cutoff { - discard; - } -#else // BLEND_PREMULTIPLIED_ALPHA || BLEND_ALPHA let alpha_mode = material.flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; - if (alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND || alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD) - && output_color.a < PREMULTIPLIED_ALPHA_CUTOFF { - discard; - } else if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_PREMULTIPLIED - && all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) { - discard; + if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK { + if output_color.a < material.alpha_cutoff { + discard; + } + } else if (alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND || alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD) { + if output_color.a < PREMULTIPLIED_ALPHA_CUTOFF { + discard; + } + } else if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_PREMULTIPLIED { + if all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) { + discard; + } } -#endif // !ALPHA_MASK -#endif // EMPTY_PREPASS_ALPHA_DISCARD not defined +#endif // MAY_DISCARD } #ifdef PREPASS_FRAGMENT