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.
This commit is contained in:
robtfm 2023-03-05 00:17:44 +00:00
parent f87de36843
commit 6124b20f4b
5 changed files with 32 additions and 28 deletions

View file

@ -445,14 +445,19 @@ pub fn queue_material_meshes<M: Material>(
let mut mesh_key = let mut mesh_key =
MeshPipelineKey::from_primitive_topology(mesh.primitive_topology) MeshPipelineKey::from_primitive_topology(mesh.primitive_topology)
| view_key; | view_key;
let alpha_mode = material.properties.alpha_mode; match material.properties.alpha_mode {
if let AlphaMode::Blend | AlphaMode::Premultiplied | AlphaMode::Add = alpha_mode AlphaMode::Blend => {
{ mesh_key |= MeshPipelineKey::BLEND_ALPHA;
// Blend, Premultiplied and Add all share the same pipeline key }
// They're made distinct in the PBR shader, via `premultiply_alpha()` AlphaMode::Premultiplied | AlphaMode::Add => {
mesh_key |= MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA; // Premultiplied and Add share the same pipeline key
} else if let AlphaMode::Multiply = alpha_mode { // They're made distinct in the PBR shader, via `premultiply_alpha()`
mesh_key |= MeshPipelineKey::BLEND_MULTIPLY; mesh_key |= MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA;
}
AlphaMode::Multiply => {
mesh_key |= MeshPipelineKey::BLEND_MULTIPLY;
}
_ => (),
} }
let pipeline_id = pipelines.specialize( let pipeline_id = pipelines.specialize(
@ -474,7 +479,7 @@ pub fn queue_material_meshes<M: Material>(
let distance = rangefinder.distance(&mesh_uniform.transform) let distance = rangefinder.distance(&mesh_uniform.transform)
+ material.properties.depth_bias; + material.properties.depth_bias;
match alpha_mode { match material.properties.alpha_mode {
AlphaMode::Opaque => { AlphaMode::Opaque => {
opaque_phase.add(Opaque3d { opaque_phase.add(Opaque3d {
entity: *visible_entity, entity: *visible_entity,

View file

@ -235,6 +235,9 @@ where
if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA { if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into()); 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) { if layout.contains(Mesh::ATTRIBUTE_POSITION) {
shader_defs.push("VERTEX_POSITIONS".into()); 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 // 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) let fragment = if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS)
|| ((key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) || ((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()) && self.material_fragment_shader.is_some())
{ {
// Use the fragment shader from the material if present // Use the fragment shader from the material if present

View file

@ -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_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_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_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 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 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; 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 (label, blend, depth_write_enabled);
let pass = key.intersection(MeshPipelineKey::BLEND_RESERVED_BITS); 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(); label = "premultiplied_alpha_mesh_pipeline".into();
blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING); blend = Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING);
shader_defs.push("PREMULTIPLY_ALPHA".into()); shader_defs.push("PREMULTIPLY_ALPHA".into());

View file

@ -327,19 +327,7 @@ fn premultiply_alpha(standard_material_flags: u32, color: vec4<f32>) -> vec4<f32
// //
// result = 1 * src_color + (1 - src_alpha) * dst_color // result = 1 * src_color + (1 - src_alpha) * dst_color
let alpha_mode = standard_material_flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; let alpha_mode = standard_material_flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND { if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD {
// Here, we premultiply `src_color` by `src_alpha` (ahead of time, here in the shader)
//
// src_color *= src_alpha
//
// We end up with:
//
// result = 1 * (src_alpha * src_color) + (1 - src_alpha) * dst_color
// result = src_alpha * src_color + (1 - src_alpha) * dst_color
//
// Which is the blend operation for regular alpha blending `BlendState::ALPHA_BLENDING`
return vec4<f32>(color.rgb * color.a, color.a);
} else if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD {
// Here, we premultiply `src_color` by `src_alpha`, and replace `src_alpha` with 0.0: // Here, we premultiply `src_color` by `src_alpha`, and replace `src_alpha` with 0.0:
// //
// src_color *= src_alpha // src_color *= src_alpha

View file

@ -28,9 +28,11 @@ fn prepass_alpha_discard(in: FragmentInput) {
// #if defined(ALPHA_MASK) || defined(BLEND_PREMULTIPLIED_ALPHA) // #if defined(ALPHA_MASK) || defined(BLEND_PREMULTIPLIED_ALPHA)
#ifndef ALPHA_MASK #ifndef ALPHA_MASK
#ifndef BLEND_PREMULTIPLIED_ALPHA #ifndef BLEND_PREMULTIPLIED_ALPHA
#ifndef BLEND_ALPHA
#define EMPTY_PREPASS_ALPHA_DISCARD #define EMPTY_PREPASS_ALPHA_DISCARD
#endif // BLEND_ALPHA
#endif // BLEND_PREMULTIPLIED_ALPHA not defined #endif // BLEND_PREMULTIPLIED_ALPHA not defined
#endif // ALPHA_MASK 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 { if ((material.flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK) != 0u) && output_color.a < material.alpha_cutoff {
discard; discard;
} }
#endif // ALPHA_MASK #else // BLEND_PREMULTIPLIED_ALPHA || BLEND_ALPHA
#ifdef BLEND_PREMULTIPLIED_ALPHA
let alpha_mode = material.flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; 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) if (alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND || alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD)
&& output_color.a < PREMULTIPLIED_ALPHA_CUTOFF { && output_color.a < PREMULTIPLIED_ALPHA_CUTOFF {
@ -58,7 +58,7 @@ fn prepass_alpha_discard(in: FragmentInput) {
&& all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) { && all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) {
discard; discard;
} }
#endif // BLEND_PREMULTIPLIED_ALPHA #endif // !ALPHA_MASK
#endif // EMPTY_PREPASS_ALPHA_DISCARD not defined #endif // EMPTY_PREPASS_ALPHA_DISCARD not defined
} }