diff --git a/crates/bevy_pbr/src/decal/forward.rs b/crates/bevy_pbr/src/decal/forward.rs index c90c1f00f049c..f2d126fea51bf 100644 --- a/crates/bevy_pbr/src/decal/forward.rs +++ b/crates/bevy_pbr/src/decal/forward.rs @@ -11,7 +11,6 @@ use bevy_math::{prelude::Rectangle, Quat, Vec2, Vec3}; use bevy_mesh::{Mesh, Mesh3d, MeshBuilder, MeshVertexBufferLayoutRef, Meshable}; use bevy_reflect::{Reflect, TypePath}; use bevy_render::{ - alpha::AlphaMode, render_asset::RenderAssets, render_resource::{ AsBindGroup, AsBindGroupShaderType, CompareFunction, RenderPipelineDescriptor, ShaderType, @@ -47,7 +46,7 @@ impl Plugin for ForwardDecalPlugin { } } -/// A decal that renders via a 1x1 transparent quad mesh, smoothly alpha-blending with the underlying +/// A decal that renders via a 1x1 quad mesh, smoothly alpha-blending with the underlying /// geometry towards the edges. /// /// Because forward decals are meshes, you can use arbitrary materials to control their appearance. @@ -91,6 +90,8 @@ pub struct ForwardDecalMaterialExt { /// blending with more distant surfaces. /// /// Units are in meters. + /// + /// This has no effect if alpha mode is `Opaque`. pub depth_fade_factor: f32, } @@ -111,8 +112,8 @@ impl AsBindGroupShaderType for ForwardDecalMater } impl MaterialExtension for ForwardDecalMaterialExt { - fn alpha_mode() -> Option { - Some(AlphaMode::Blend) + fn enable_prepass() -> bool { + false // This is needed if alpha mode is `Opaque`. } fn enable_shadows() -> bool { diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 3e3842a23faf5..fdc22f47a3b6e 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -2462,8 +2462,9 @@ impl SpecializedMeshPipeline for MeshPipeline { let (mut is_opaque, mut alpha_to_coverage_enabled) = (false, false); if key.contains(MeshPipelineKey::OIT_ENABLED) && pass == MeshPipelineKey::BLEND_ALPHA { label = "oit_mesh_pipeline".into(); - // TODO tail blending would need alpha blending - blend = None; + // TODO tail blending would need to return color in shader to do alpha blending + // Alpha blending is also needed by forward decals. + blend = Some(BlendState::ALPHA_BLENDING); shader_defs.push("OIT_ENABLED".into()); // TODO it should be possible to use this to combine MSAA and OIT // alpha_to_coverage_enabled = true; diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index ea2b33ee0ac11..4beb3949191e5 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -89,6 +89,11 @@ fn fragment( out.color = main_pass_post_lighting_processing(pbr_input, out.color); #endif +#ifdef FORWARD_DECAL + out.color.a = min(forward_decal_info.alpha, out.color.a); +#else +// Forward decal is incompatible with OIT as it needs to be rendered +// even it's occluded by opaque objects, but OIT will exclude the fragments. #ifdef OIT_ENABLED let alpha_mode = pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; if alpha_mode != pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE { @@ -97,9 +102,6 @@ fn fragment( discard; } #endif // OIT_ENABLED - -#ifdef FORWARD_DECAL - out.color.a = min(forward_decal_info.alpha, out.color.a); #endif return out; diff --git a/examples/3d/decal.rs b/examples/3d/decal.rs index 623227cf2ffd9..79e269d8cb7e6 100644 --- a/examples/3d/decal.rs +++ b/examples/3d/decal.rs @@ -27,18 +27,58 @@ fn setup( ) { // Spawn the forward decal commands.spawn(( - Name::new("Decal"), + Name::new("Decal Red"), ForwardDecal, MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { base: StandardMaterial { base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), + base_color: Color::srgba(1.0, 0.0, 0.0, 0.5), + // Alpha mode for decals. Other alpha modes are also supported. + alpha_mode: AlphaMode::Blend, + depth_bias: 0.0, ..default() }, extension: ForwardDecalMaterialExt { depth_fade_factor: 1.0, }, })), - Transform::from_scale(Vec3::splat(4.0)), + Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(1.0, 0.0, -1.0)), + )); + + commands.spawn(( + Name::new("Decal Green"), + ForwardDecal, + MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { + base: StandardMaterial { + base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), + base_color: Color::srgba(0.0, 1.0, 0.0, 0.5), + alpha_mode: AlphaMode::Blend, + depth_bias: 2.0, + ..default() + }, + extension: ForwardDecalMaterialExt { + depth_fade_factor: 1.0, + }, + })), + Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(-1.0, 0.0, -1.0)), + )); + + commands.spawn(( + Name::new("Decal Blue"), + ForwardDecal, + MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial { + base: StandardMaterial { + base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")), + base_color: Color::srgba(0.0, 0.0, 1.0, 0.5), + alpha_mode: AlphaMode::Blend, + depth_bias: 4.0, + ..default() + }, + extension: ForwardDecalMaterialExt { + depth_fade_factor: 1.0, + }, + })), + Transform::from_scale(Vec3::splat(4.0)).with_translation(Vec3::new(0.0, 0.0, 1.0)), )); commands.spawn((