Skip to content

Commit

Permalink
use blendstate blend for alphamode::blend (bevyengine#7899)
Browse files Browse the repository at this point in the history
# 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.
  • Loading branch information
robtfm committed Mar 5, 2023
1 parent f87de36 commit 6124b20
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 28 deletions.
23 changes: 14 additions & 9 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,14 +445,19 @@ pub fn queue_material_meshes<M: Material>(
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(
Expand All @@ -474,7 +479,7 @@ pub fn queue_material_meshes<M: Material>(

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,
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down
14 changes: 1 addition & 13 deletions crates/bevy_pbr/src/render/pbr_functions.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
let alpha_mode = standard_material_flags & STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
if alpha_mode == STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND {
// 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 {
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
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_pbr/src/render/pbr_prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 {
Expand All @@ -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
}
Expand Down

0 comments on commit 6124b20

Please sign in to comment.