From 6124b20f4bb6c706f01c7a71259989696c91dea5 Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Sun, 5 Mar 2023 00:17:44 +0000 Subject: [PATCH] use blendstate blend for alphamode::blend (#7899) # Objective revert combining pipelines for AlphaMode::Blend and AlphaMode::Premultiplied & Add the recent blend state pr changed `AlphaMode::Blend` to use a blend state of `Blend::PREMULTIPLIED_ALPHA_BLENDING`, and recovered the original behaviour by multiplying colour by alpha in the standard material's fragment shader. this had some advantages (specifically it means more material instances can be batched together in future), but this also means that custom materials that specify `AlphaMode::Blend` now get a premultiplied blend state, so they must also multiply colour by alpha. ## Solution revert that combination to preserve 0.9 behaviour for custom materials with AlphaMode::Blend. --- crates/bevy_pbr/src/material.rs | 23 +++++++++++-------- crates/bevy_pbr/src/prepass/mod.rs | 6 ++++- crates/bevy_pbr/src/render/mesh.rs | 9 +++++++- crates/bevy_pbr/src/render/pbr_functions.wgsl | 14 +---------- crates/bevy_pbr/src/render/pbr_prepass.wgsl | 8 +++---- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 9a2ead7c7232b..cb57e68f4d0dd 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -445,14 +445,19 @@ pub fn queue_material_meshes( let mut mesh_key = MeshPipelineKey::from_primitive_topology(mesh.primitive_topology) | view_key; - let alpha_mode = material.properties.alpha_mode; - if let AlphaMode::Blend | AlphaMode::Premultiplied | AlphaMode::Add = alpha_mode - { - // Blend, Premultiplied and Add all share the same pipeline key - // They're made distinct in the PBR shader, via `premultiply_alpha()` - mesh_key |= MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA; - } else if let AlphaMode::Multiply = alpha_mode { - mesh_key |= MeshPipelineKey::BLEND_MULTIPLY; + match material.properties.alpha_mode { + AlphaMode::Blend => { + mesh_key |= MeshPipelineKey::BLEND_ALPHA; + } + AlphaMode::Premultiplied | AlphaMode::Add => { + // Premultiplied and Add share the same pipeline key + // They're made distinct in the PBR shader, via `premultiply_alpha()` + mesh_key |= MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA; + } + AlphaMode::Multiply => { + mesh_key |= MeshPipelineKey::BLEND_MULTIPLY; + } + _ => (), } let pipeline_id = pipelines.specialize( @@ -474,7 +479,7 @@ pub fn queue_material_meshes( let distance = rangefinder.distance(&mesh_uniform.transform) + material.properties.depth_bias; - match alpha_mode { + match material.properties.alpha_mode { AlphaMode::Opaque => { opaque_phase.add(Opaque3d { entity: *visible_entity, diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 407c357a230e4..855d1e4ae8e33 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -235,6 +235,9 @@ where if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA { shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into()); } + if blend_key == MeshPipelineKey::BLEND_ALPHA { + shader_defs.push("BLEND_ALPHA".into()); + } if layout.contains(Mesh::ATTRIBUTE_POSITION) { shader_defs.push("VERTEX_POSITIONS".into()); @@ -285,7 +288,8 @@ where // or the material uses alpha cutoff values and doesn't rely on the standard prepass shader let fragment = if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) || ((key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) - || blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA) + || blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA + || blend_key == MeshPipelineKey::BLEND_ALPHA) && self.material_fragment_shader.is_some()) { // Use the fragment shader from the material if present diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 67bb0c7138196..9b1239099bfd8 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -574,6 +574,7 @@ bitflags::bitflags! { const BLEND_OPAQUE = (0 << Self::BLEND_SHIFT_BITS); // ← Values are just sequential within the mask, and can range from 0 to 3 const BLEND_PREMULTIPLIED_ALPHA = (1 << Self::BLEND_SHIFT_BITS); // const BLEND_MULTIPLY = (2 << Self::BLEND_SHIFT_BITS); // ← We still have room for one more value without adding more bits + const BLEND_ALPHA = (3 << Self::BLEND_SHIFT_BITS); const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; const PRIMITIVE_TOPOLOGY_RESERVED_BITS = Self::PRIMITIVE_TOPOLOGY_MASK_BITS << Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS; const TONEMAP_METHOD_RESERVED_BITS = Self::TONEMAP_METHOD_MASK_BITS << Self::TONEMAP_METHOD_SHIFT_BITS; @@ -708,7 +709,13 @@ impl SpecializedMeshPipeline for MeshPipeline { let (label, blend, depth_write_enabled); let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS); - if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA { + if pass == MeshPipelineKey::BLEND_ALPHA { + label = "alpha_blend_mesh_pipeline".into(); + blend = Some(BlendState::ALPHA_BLENDING); + // For the transparent pass, fragments that are closer will be alpha blended + // but their depth is not written to the depth buffer + depth_write_enabled = false; + } else if pass == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA { label = "premultiplied_alpha_mesh_pipeline".into(); blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING); shader_defs.push("PREMULTIPLY_ALPHA".into()); diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 5cb140b6f412f..45f42268c0e64 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -327,19 +327,7 @@ fn premultiply_alpha(standard_material_flags: u32, color: vec4) -> vec4(color.rgb * color.a, color.a); - } else if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD { + if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD { // Here, we premultiply `src_color` by `src_alpha`, and replace `src_alpha` with 0.0: // // src_color *= src_alpha diff --git a/crates/bevy_pbr/src/render/pbr_prepass.wgsl b/crates/bevy_pbr/src/render/pbr_prepass.wgsl index e6efe84c34681..a305e658b9207 100644 --- a/crates/bevy_pbr/src/render/pbr_prepass.wgsl +++ b/crates/bevy_pbr/src/render/pbr_prepass.wgsl @@ -28,9 +28,11 @@ fn prepass_alpha_discard(in: FragmentInput) { // #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 @@ -47,9 +49,7 @@ fn prepass_alpha_discard(in: FragmentInput) { if ((material.flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK) != 0u) && output_color.a < material.alpha_cutoff { discard; } -#endif // ALPHA_MASK - -#ifdef BLEND_PREMULTIPLIED_ALPHA +#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 { @@ -58,7 +58,7 @@ fn prepass_alpha_discard(in: FragmentInput) { && all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) { discard; } -#endif // BLEND_PREMULTIPLIED_ALPHA +#endif // !ALPHA_MASK #endif // EMPTY_PREPASS_ALPHA_DISCARD not defined }