bevy_pbr/decal/
forward.rs1use crate::{
2 ExtendedMaterial, Material, MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline,
3 MaterialPlugin, StandardMaterial,
4};
5use bevy_app::{App, Plugin};
6use bevy_asset::{load_internal_asset, weak_handle, Asset, Assets, Handle};
7use bevy_ecs::component::Component;
8use bevy_math::{prelude::Rectangle, Quat, Vec2, Vec3};
9use bevy_reflect::{Reflect, TypePath};
10use bevy_render::render_asset::RenderAssets;
11use bevy_render::render_resource::{AsBindGroupShaderType, ShaderType};
12use bevy_render::texture::GpuImage;
13use bevy_render::{
14 alpha::AlphaMode,
15 mesh::{Mesh, Mesh3d, MeshBuilder, MeshVertexBufferLayoutRef, Meshable},
16 render_resource::{
17 AsBindGroup, CompareFunction, RenderPipelineDescriptor, Shader,
18 SpecializedMeshPipelineError,
19 },
20 RenderDebugFlags,
21};
22
23const FORWARD_DECAL_MESH_HANDLE: Handle<Mesh> =
24 weak_handle!("afa817f9-1869-4e0c-ac0d-d8cd1552d38a");
25const FORWARD_DECAL_SHADER_HANDLE: Handle<Shader> =
26 weak_handle!("f8dfbef4-d88b-42ae-9af4-d9661e9f1648");
27
28pub struct ForwardDecalPlugin;
30
31impl Plugin for ForwardDecalPlugin {
32 fn build(&self, app: &mut App) {
33 load_internal_asset!(
34 app,
35 FORWARD_DECAL_SHADER_HANDLE,
36 "forward_decal.wgsl",
37 Shader::from_wgsl
38 );
39
40 app.register_type::<ForwardDecal>();
41
42 app.world_mut().resource_mut::<Assets<Mesh>>().insert(
43 FORWARD_DECAL_MESH_HANDLE.id(),
44 Rectangle::from_size(Vec2::ONE)
45 .mesh()
46 .build()
47 .rotated_by(Quat::from_rotation_arc(Vec3::Z, Vec3::Y))
48 .with_generated_tangents()
49 .unwrap(),
50 );
51
52 app.add_plugins(MaterialPlugin::<ForwardDecalMaterial<StandardMaterial>> {
53 prepass_enabled: false,
54 shadows_enabled: false,
55 debug_flags: RenderDebugFlags::default(),
56 ..Default::default()
57 });
58 }
59}
60
61#[derive(Component, Reflect)]
73#[require(Mesh3d(FORWARD_DECAL_MESH_HANDLE))]
74pub struct ForwardDecal;
75
76#[expect(type_alias_bounds, reason = "Type alias generics not yet stable")]
82pub type ForwardDecalMaterial<B: Material> = ExtendedMaterial<B, ForwardDecalMaterialExt>;
83
84#[derive(Asset, AsBindGroup, TypePath, Clone, Debug)]
92#[uniform(200, ForwardDecalMaterialExtUniform)]
93pub struct ForwardDecalMaterialExt {
94 pub depth_fade_factor: f32,
104}
105
106#[derive(Clone, Default, ShaderType)]
107pub struct ForwardDecalMaterialExtUniform {
108 pub inv_depth_fade_factor: f32,
109}
110
111impl AsBindGroupShaderType<ForwardDecalMaterialExtUniform> for ForwardDecalMaterialExt {
112 fn as_bind_group_shader_type(
113 &self,
114 _images: &RenderAssets<GpuImage>,
115 ) -> ForwardDecalMaterialExtUniform {
116 ForwardDecalMaterialExtUniform {
117 inv_depth_fade_factor: 1.0 / self.depth_fade_factor.max(0.001),
118 }
119 }
120}
121
122impl MaterialExtension for ForwardDecalMaterialExt {
123 fn alpha_mode() -> Option<AlphaMode> {
124 Some(AlphaMode::Blend)
125 }
126
127 fn specialize(
128 _pipeline: &MaterialExtensionPipeline,
129 descriptor: &mut RenderPipelineDescriptor,
130 _layout: &MeshVertexBufferLayoutRef,
131 _key: MaterialExtensionKey<Self>,
132 ) -> Result<(), SpecializedMeshPipelineError> {
133 descriptor.depth_stencil.as_mut().unwrap().depth_compare = CompareFunction::Always;
134
135 descriptor.vertex.shader_defs.push("FORWARD_DECAL".into());
136
137 if let Some(fragment) = &mut descriptor.fragment {
138 fragment.shader_defs.push("FORWARD_DECAL".into());
139 }
140
141 if let Some(label) = &mut descriptor.label {
142 *label = format!("forward_decal_{}", label).into();
143 }
144
145 Ok(())
146 }
147}
148
149impl Default for ForwardDecalMaterialExt {
150 fn default() -> Self {
151 Self {
152 depth_fade_factor: 8.0,
153 }
154 }
155}