1use crate::{
2 irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE, MeshPipeline, MeshPipelineKey,
3 MeshPipelineSystems, MeshViewBindGroup, ViewKeyCache, TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
4 TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
5};
6use bevy_app::prelude::*;
7use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
8use bevy_core_pipeline::{
9 core_3d::main_opaque_pass_3d,
10 deferred::{
11 copy_lighting_id::DeferredLightingIdDepthTexture, DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
12 },
13 prepass::DeferredPrepass,
14 schedule::{Core3d, Core3dSystems},
15};
16use bevy_ecs::prelude::*;
17use bevy_render::{
18 camera::ExtractedCamera,
19 diagnostic::RecordDiagnostics,
20 extract_component::{
21 ComponentUniforms, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin,
22 },
23 render_resource::{binding_types::uniform_buffer, *},
24 renderer::{RenderContext, ViewQuery},
25 view::{ExtractedView, ViewTarget},
26 Render, RenderApp, RenderSystems,
27};
28use bevy_render::{GpuResourceAppExt, RenderStartup};
29use bevy_shader::{Shader, ShaderDefVal};
30use bevy_utils::default;
31
32pub struct DeferredPbrLightingPlugin;
33
34pub const DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID: u8 = 1;
35
36#[derive(impl bevy_ecs::component::Component for PbrDeferredLightingDepthId where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}Component, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PbrDeferredLightingDepthId { }
#[automatically_derived]
impl ::core::clone::Clone for PbrDeferredLightingDepthId {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for PbrDeferredLightingDepthId { }Copy, impl bevy_extract::sync_component::SyncComponent<RenderApp> for
PbrDeferredLightingDepthId where Self: ::core::clone::Clone {
type Target = Self;
}
impl bevy_extract::extract_component::ExtractComponent<RenderApp> for
PbrDeferredLightingDepthId where Self: ::core::clone::Clone {
type QueryData = &'static Self;
type QueryFilter = ();
type Out = Self;
fn extract_component(item:
bevy_ecs::query::QueryItem<'_, '_, Self::QueryData>)
-> ::core::option::Option<Self::Out> {
::core::option::Option::Some(item.clone())
}
}ExtractComponent, impl bevy_render::render_resource::encase::private::ShaderType for
PbrDeferredLightingDepthId where
u32: bevy_render::render_resource::encase::private::ShaderType {
type ExtraMetadata =
bevy_render::render_resource::encase::private::StructMetadata<1usize>;
const METADATA:
bevy_render::render_resource::encase::private::Metadata<Self::ExtraMetadata>
=
{
let struct_alignment =
bevy_render::render_resource::encase::private::AlignmentValue::max([<u32
as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.alignment()]);
let extra =
{
let mut paddings = [0; 1usize];
let mut offsets = [0; 1usize];
let mut offset = 0;
offset +=
<u32 as
bevy_render::render_resource::encase::private::ShaderSize>::SHADER_SIZE.get();
paddings[0usize] =
struct_alignment.padding_needed_for(offset);
bevy_render::render_resource::encase::private::StructMetadata {
offsets,
paddings,
}
};
let min_size =
{
let mut offset = extra.offsets[1usize - 1];
offset +=
<u32 as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.min_size().get();
bevy_render::render_resource::encase::private::SizeValue::new(struct_alignment.round_up(offset))
};
bevy_render::render_resource::encase::private::Metadata {
alignment: struct_alignment,
has_uniform_min_alignment: true,
min_size,
is_pod: false,
extra,
}
};
const UNIFORM_COMPAT_ASSERT: fn() =
||
bevy_render::render_resource::encase::private::consume_zsts([<u32
as
bevy_render::render_resource::encase::private::ShaderType>::UNIFORM_COMPAT_ASSERT(),
if let ::core::option::Option::Some(min_alignment) =
<u32 as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.uniform_min_alignment()
{
let offset =
<Self as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.offset(0usize);
{
#[allow(clippy :: equatable_if_let)]
if let false = min_alignment.is_aligned(offset) {
{
let mut fmt: ::const_panic::FmtArg =
::const_panic::FmtArg::DEBUG;
match &[::const_panic::StdWrapper(&match &"offset of field '"
{
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt.set_display().set_alternate(false))).deref_panic_vals(),
::const_panic::StdWrapper(&match &"depth_id" {
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt.set_display().set_alternate(false))).deref_panic_vals(),
::const_panic::StdWrapper(&match &"' must be a multiple of "
{
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt.set_display().set_alternate(false))).deref_panic_vals(),
::const_panic::StdWrapper(&match &min_alignment.get() {
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt)).deref_panic_vals(),
::const_panic::StdWrapper(&match &" (current offset: " {
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt.set_display().set_alternate(false))).deref_panic_vals(),
::const_panic::StdWrapper(&match &offset {
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt)).deref_panic_vals(),
::const_panic::StdWrapper(&match &")" {
reff =>
::const_panic::__::PanicFmt::PROOF.infer(reff).coerce(reff),
}.to_panicvals(fmt.set_display().set_alternate(false))).deref_panic_vals()]
{
args => ::const_panic::concat_panic(args),
}
}
}
}
}, ()]);
fn size(&self) -> ::core::num::NonZeroU64 {
let mut offset = Self::METADATA.last_offset();
offset +=
bevy_render::render_resource::encase::private::ShaderType::size(&self.depth_id).get();
bevy_render::render_resource::encase::private::SizeValue::new(Self::METADATA.alignment().round_up(offset)).0
}
}
impl bevy_render::render_resource::encase::private::WriteInto for
PbrDeferredLightingDepthId where
Self: bevy_render::render_resource::encase::private::ShaderType<ExtraMetadata
= bevy_render::render_resource::encase::private::StructMetadata<1usize>>,
for<'__> u32: bevy_render::render_resource::encase::private::WriteInto {
#[inline]
fn write_into<B: bevy_render::render_resource::encase::private::BufferMut>(&self,
writer:
&mut bevy_render::render_resource::encase::private::Writer<B>) {
bevy_render::render_resource::encase::private::WriteInto::write_into(&self.depth_id,
writer);
bevy_render::render_resource::encase::private::Writer::advance(writer,
<Self as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.padding(0usize)
as ::core::primitive::usize);
}
}
impl bevy_render::render_resource::encase::private::ReadFrom for
PbrDeferredLightingDepthId where
Self: bevy_render::render_resource::encase::private::ShaderType<ExtraMetadata
= bevy_render::render_resource::encase::private::StructMetadata<1usize>>,
for<'__> u32: bevy_render::render_resource::encase::private::ReadFrom {
#[inline]
fn read_from<B: bevy_render::render_resource::encase::private::BufferRef>(&mut self,
reader:
&mut bevy_render::render_resource::encase::private::Reader<B>) {
bevy_render::render_resource::encase::private::ReadFrom::read_from(&mut self.depth_id,
reader);
bevy_render::render_resource::encase::private::Reader::advance(reader,
<Self as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.padding(0usize)
as ::core::primitive::usize);
}
}
impl bevy_render::render_resource::encase::private::CreateFrom for
PbrDeferredLightingDepthId where
Self: bevy_render::render_resource::encase::private::ShaderType<ExtraMetadata
= bevy_render::render_resource::encase::private::StructMetadata<1usize>>,
for<'__> u32: bevy_render::render_resource::encase::private::CreateFrom {
#[inline]
fn create_from<B: bevy_render::render_resource::encase::private::BufferRef>(reader:
&mut bevy_render::render_resource::encase::private::Reader<B>)
-> Self {
let depth_id =
bevy_render::render_resource::encase::private::CreateFrom::create_from(reader);
bevy_render::render_resource::encase::private::Reader::advance(reader,
<Self as
bevy_render::render_resource::encase::private::ShaderType>::METADATA.padding(0usize)
as ::core::primitive::usize);
{
let mut uninit_struct =
::core::mem::MaybeUninit::<Self>::uninit();
let ptr =
::core::mem::MaybeUninit::as_mut_ptr(&mut uninit_struct);
let field_ptr = unsafe { &raw mut (*ptr).depth_id };
unsafe { field_ptr.write(depth_id) };
;
unsafe { ::core::mem::MaybeUninit::assume_init(uninit_struct) }
}
}
}
impl bevy_render::render_resource::encase::private::ShaderSize for
PbrDeferredLightingDepthId where
u32: bevy_render::render_resource::encase::private::ShaderSize {}ShaderType)]
40#[extract_app(RenderApp)]
41pub struct PbrDeferredLightingDepthId {
42 depth_id: u32,
43
44 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
45 _webgl2_padding_0: f32,
46 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
47 _webgl2_padding_1: f32,
48 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
49 _webgl2_padding_2: f32,
50}
51
52impl PbrDeferredLightingDepthId {
53 pub fn new(value: u8) -> PbrDeferredLightingDepthId {
54 PbrDeferredLightingDepthId {
55 depth_id: value as u32,
56
57 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
58 _webgl2_padding_0: 0.0,
59 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
60 _webgl2_padding_1: 0.0,
61 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
62 _webgl2_padding_2: 0.0,
63 }
64 }
65
66 pub fn set(&mut self, value: u8) {
67 self.depth_id = value as u32;
68 }
69
70 pub fn get(&self) -> u8 {
71 self.depth_id as u8
72 }
73}
74
75impl Default for PbrDeferredLightingDepthId {
76 fn default() -> Self {
77 PbrDeferredLightingDepthId {
78 depth_id: DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID as u32,
79
80 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
81 _webgl2_padding_0: 0.0,
82 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
83 _webgl2_padding_1: 0.0,
84 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
85 _webgl2_padding_2: 0.0,
86 }
87 }
88}
89
90impl Plugin for DeferredPbrLightingPlugin {
91 fn build(&self, app: &mut App) {
92 app.add_plugins((
93 ExtractComponentPlugin::<PbrDeferredLightingDepthId>::default(),
94 UniformComponentPlugin::<PbrDeferredLightingDepthId>::default(),
95 ))
96 .add_systems(PostUpdate, insert_deferred_lighting_pass_id_component);
97
98 {
{
let mut embedded =
app.world_mut().resource_mut::<::bevy_asset::io::embedded::EmbeddedAssetRegistry>();
let path =
{
let crate_name =
"bevy_pbr::deferred".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/deferred/mod.rs".as_ref(),
"deferred_lighting.wesl".as_ref())
};
let watched_path =
::bevy_asset::io::embedded::watched_path("src/deferred/mod.rs",
"deferred_lighting.wesl");
embedded.insert_asset(watched_path, &path,
b"import package::{\n prepass::utils as prepass_utils,\n render::{\n pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT,\n pbr_functions,\n pbr_lighting as lighting,\n mesh_view_bindings::{deferred_prepass_texture, view},\n },\n deferred::{\n functions::pbr_input_from_deferred_gbuffer,\n types::unpack_unorm3x4_plus_unorm_20_,\n },\n};\n\n@if(SCREEN_SPACE_AMBIENT_OCCLUSION) import package::render::mesh_view_bindings::screen_space_ambient_occlusion_texture;\n@if(SCREEN_SPACE_AMBIENT_OCCLUSION) import package::ssao::utils::ssao_multibounce;\n\nstruct FullscreenVertexOutput {\n @builtin(position)\n position: vec4<f32>,\n @location(0)\n uv: vec2<f32>,\n};\n\nstruct PbrDeferredLightingDepthId {\n depth_id: u32, // limited to u8\n @if(SIXTEEN_BYTE_ALIGNMENT)\n // WebGL2 structs must be 16 byte aligned.\n _webgl2_padding_0: f32,\n @if(SIXTEEN_BYTE_ALIGNMENT)\n _webgl2_padding_1: f32,\n @if(SIXTEEN_BYTE_ALIGNMENT)\n _webgl2_padding_2: f32,\n}\n@group(2) @binding(0)\nvar<uniform> depth_id: PbrDeferredLightingDepthId;\n\n@vertex\nfn vertex(@builtin(vertex_index) vertex_index: u32) -> FullscreenVertexOutput {\n // See the full screen vertex shader for explanation above for how this works.\n let uv = vec2<f32>(f32(vertex_index >> 1u), f32(vertex_index & 1u)) * 2.0;\n // Depth is stored as unorm, so we are dividing the u8 depth_id by 255.0 here.\n let clip_position = vec4<f32>(uv * vec2<f32>(2.0, -2.0) + vec2<f32>(-1.0, 1.0), f32(depth_id.depth_id) / 255.0, 1.0);\n\n return FullscreenVertexOutput(clip_position, uv);\n}\n\n@fragment\nfn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {\n var frag_coord = vec4(in.position.xy, 0.0, 0.0);\n\n let deferred_data = textureLoad(deferred_prepass_texture, vec2<i32>(frag_coord.xy), 0);\n\n @if(WEBGL2)\n frag_coord.z = unpack_unorm3x4_plus_unorm_20_(deferred_data.b).w;\n @elif(DEPTH_PREPASS)\n frag_coord.z = prepass_utils::prepass_depth(in.position, 0u);\n\n var pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, deferred_data);\n var output_color = vec4(0.0);\n\n // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit\n if ((pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {\n\n@if(SCREEN_SPACE_AMBIENT_OCCLUSION) {\n let ssao_tex_pos = vec2<i32>(in.position.xy - view.viewport.xy);\n let ssao = textureLoad(screen_space_ambient_occlusion_texture, ssao_tex_pos, 0i).r;\n let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);\n pbr_input.diffuse_occlusion = min(pbr_input.diffuse_occlusion, ssao_multibounce);\n\n // Neubelt and Pettineo 2013, \"Crafting a Next-gen Material Pipeline for The Order: 1886\"\n let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001); \n var perceptual_roughness: f32 = pbr_input.material.perceptual_roughness;\n let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);\n // Use SSAO to estimate the specular occlusion.\n // Lagarde and Rousiers 2014, \"Moving Frostbite to Physically Based Rendering\"\n pbr_input.specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);\n}\n\n output_color = pbr_functions::apply_pbr_lighting(pbr_input);\n } else {\n output_color = pbr_input.material.base_color;\n }\n\n output_color = pbr_functions::main_pass_post_lighting_processing(pbr_input, output_color);\n\n return output_color;\n}\n");
}
};embedded_asset!(app, "deferred_lighting.wesl");
99
100 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
101 return;
102 };
103
104 render_app
105 .init_gpu_resource::<SpecializedRenderPipelines<DeferredLightingLayout>>()
106 .add_systems(
107 RenderStartup,
108 init_deferred_lighting_layout.after(MeshPipelineSystems),
109 )
110 .add_systems(
111 Render,
112 prepare_deferred_lighting_pipelines.in_set(RenderSystems::Prepare),
113 )
114 .add_systems(
115 Core3d,
116 deferred_lighting
117 .before(main_opaque_pass_3d)
118 .in_set(Core3dSystems::MainPass),
119 );
120 }
121}
122
123pub fn deferred_lighting(
124 view: ViewQuery<(
125 &MeshViewBindGroup,
126 &ViewTarget,
127 &DeferredLightingIdDepthTexture,
128 &DeferredLightingPipeline,
129 )>,
130 pipeline_cache: Res<PipelineCache>,
131 deferred_lighting_layout: Res<DeferredLightingLayout>,
132 deferred_lighting_pass_id: Res<ComponentUniforms<PbrDeferredLightingDepthId>>,
133 mut ctx: RenderContext,
134) {
135 let (
136 mesh_view_bind_group,
137 target,
138 deferred_lighting_id_depth_texture,
139 deferred_lighting_pipeline,
140 ) = view.into_inner();
141
142 let Some(pipeline) = pipeline_cache.get_render_pipeline(deferred_lighting_pipeline.pipeline_id)
143 else {
144 return;
145 };
146
147 let Some(deferred_lighting_pass_id_binding) = deferred_lighting_pass_id.uniforms().binding()
148 else {
149 return;
150 };
151
152 let diagnostics = ctx.diagnostic_recorder();
153 let diagnostics = diagnostics.as_deref();
154
155 let bind_group_2 = ctx.render_device().create_bind_group(
156 "deferred_lighting_layout_group_2",
157 &pipeline_cache.get_bind_group_layout(&deferred_lighting_layout.bind_group_layout_2),
158 &BindGroupEntries::single(deferred_lighting_pass_id_binding),
159 );
160
161 let mut render_pass = ctx.begin_tracked_render_pass(RenderPassDescriptor {
162 label: Some("deferred_lighting"),
163 color_attachments: &[Some(target.get_color_attachment())],
164 depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
165 view: &deferred_lighting_id_depth_texture.texture.default_view,
166 depth_ops: Some(Operations {
167 load: LoadOp::Load,
168 store: StoreOp::Discard,
169 }),
170 stencil_ops: None,
171 }),
172 timestamp_writes: None,
173 occlusion_query_set: None,
174 multiview_mask: None,
175 });
176 let pass_span = diagnostics.pass_span(&mut render_pass, "deferred_lighting");
177
178 render_pass.set_render_pipeline(pipeline);
179
180 render_pass.set_bind_group(
181 0,
182 &mesh_view_bind_group.main,
183 &mesh_view_bind_group.main_offsets,
184 );
185 render_pass.set_bind_group(1, &mesh_view_bind_group.binding_array, &[]);
186 render_pass.set_bind_group(2, &bind_group_2, &[]);
187 render_pass.draw(0..3, 0..1);
188 pass_span.end(&mut render_pass);
189}
190
191#[derive(impl bevy_ecs::component::Component for DeferredLightingLayout where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::SparseSet;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {
let resource_component_id =
if let ::core::option::Option::Some(id) =
required_components.components_registrator().component_id::<DeferredLightingLayout>()
{
id
} else {
required_components.components_registrator().register_component::<DeferredLightingLayout>()
};
required_components.register_required::<bevy_ecs::resource::IsResource>(move
||
bevy_ecs::resource::IsResource::new(resource_component_id));
}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}
impl bevy_ecs::resource::Resource for DeferredLightingLayout where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource)]
192pub struct DeferredLightingLayout {
193 mesh_pipeline: MeshPipeline,
194 bind_group_layout_2: BindGroupLayoutDescriptor,
195 deferred_lighting_shader: Handle<Shader>,
196}
197
198#[derive(impl bevy_ecs::component::Component for DeferredLightingPipeline where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}Component)]
199pub struct DeferredLightingPipeline {
200 pub pipeline_id: CachedRenderPipelineId,
201}
202
203impl SpecializedRenderPipeline for DeferredLightingLayout {
204 type Key = MeshPipelineKey;
205
206 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
207 let mut shader_defs = Vec::new();
208
209 shader_defs.push("DEFERRED_LIGHTING_PIPELINE".into());
211
212 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
213 shader_defs.push("WEBGL2".into());
214
215 if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) {
216 shader_defs.push("TONEMAP_IN_SHADER".into());
217 shader_defs.push(ShaderDefVal::UInt(
218 "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(),
219 TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
220 ));
221 shader_defs.push(ShaderDefVal::UInt(
222 "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(),
223 TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
224 ));
225
226 let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS);
227
228 if method == MeshPipelineKey::TONEMAP_METHOD_LINEAR {
229 shader_defs.push("TONEMAP_METHOD_LINEAR".into());
230 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD {
231 shader_defs.push("TONEMAP_METHOD_REINHARD".into());
232 } else if method == MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE {
233 shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
234 } else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
235 shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
236 } else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
237 shader_defs.push("TONEMAP_METHOD_AGX".into());
238 } else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
239 shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
240 } else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
241 shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
242 } else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
243 shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
244 } else if method == MeshPipelineKey::TONEMAP_METHOD_PBR_NEUTRAL {
245 shader_defs.push("TONEMAP_METHOD_PBR_NEUTRAL".into());
246 }
247
248 if key.contains(MeshPipelineKey::DEBAND_DITHER) {
250 shader_defs.push("DEBAND_DITHER".into());
251 }
252 }
253
254 if key.contains(MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION) {
255 shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into());
256 }
257
258 if key.contains(MeshPipelineKey::ENVIRONMENT_MAP) {
259 shader_defs.push("ENVIRONMENT_MAP".into());
260 }
261
262 if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
263 shader_defs.push("IRRADIANCE_VOLUME".into());
264 }
265
266 if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
267 shader_defs.push("NORMAL_PREPASS".into());
268 }
269
270 if key.contains(MeshPipelineKey::DEPTH_PREPASS) {
271 shader_defs.push("DEPTH_PREPASS".into());
272 }
273
274 if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
275 shader_defs.push("MOTION_VECTOR_PREPASS".into());
276 }
277
278 if key.contains(MeshPipelineKey::SCREEN_SPACE_REFLECTIONS) {
279 shader_defs.push("SCREEN_SPACE_REFLECTIONS".into());
280 }
281
282 if key.contains(MeshPipelineKey::CONTACT_SHADOWS) {
283 shader_defs.push("CONTACT_SHADOWS".into());
284 }
285
286 if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
287 shader_defs.push("HAS_PREVIOUS_SKIN".into());
288 }
289
290 if key.contains(MeshPipelineKey::HAS_PREVIOUS_MORPH) {
291 shader_defs.push("HAS_PREVIOUS_MORPH".into());
292 }
293
294 if key.contains(MeshPipelineKey::DISTANCE_FOG) {
295 shader_defs.push("DISTANCE_FOG".into());
296 }
297 if key.contains(MeshPipelineKey::ATMOSPHERE) {
298 shader_defs.push("ATMOSPHERE".into());
299 }
300 shader_defs.push("STANDARD_MATERIAL_CLEARCOAT".into());
301
302 shader_defs.push("DEFERRED_PREPASS".into());
304
305 let shadow_filter_method =
306 key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS);
307 if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 {
308 shader_defs.push("SHADOW_FILTER_METHOD_HARDWARE_2X2".into());
309 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN {
310 shader_defs.push("SHADOW_FILTER_METHOD_GAUSSIAN".into());
311 } else if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL {
312 shader_defs.push("SHADOW_FILTER_METHOD_TEMPORAL".into());
313 }
314 if self.mesh_pipeline.binding_arrays_are_usable {
315 shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into());
316 shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
317 }
318
319 if IRRADIANCE_VOLUMES_ARE_USABLE {
320 shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
321 }
322
323 if self.mesh_pipeline.clustered_decals_are_usable {
324 shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
325 if truecfg!(feature = "pbr_light_textures") {
326 shader_defs.push("LIGHT_TEXTURES".into());
327 }
328 }
329
330 #[cfg(feature = "experimental_pbr_pcss")]
331 shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());
332
333 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
334 shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into());
335
336 if truecfg!(feature = "bluenoise_texture") {
337 shader_defs.push("BLUE_NOISE_TEXTURE".into());
338 }
339 if truecfg!(feature = "dfg_lut") {
340 shader_defs.push("DFG_LUT".into());
341 }
342 if truecfg!(feature = "area_light_luts") {
343 shader_defs.push("AREA_LIGHT_LUTS".into());
344 }
345
346 let layout = self.mesh_pipeline.get_view_layout(key.into());
347 RenderPipelineDescriptor {
348 label: Some("deferred_lighting_pipeline".into()),
349 layout: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[layout.main_layout, layout.binding_array_layout,
self.bind_group_layout_2.clone()]))vec![
350 layout.main_layout,
351 layout.binding_array_layout,
352 self.bind_group_layout_2.clone(),
353 ],
354 vertex: VertexState {
355 shader: self.deferred_lighting_shader.clone(),
356 shader_defs: shader_defs.clone(),
357 ..default()
358 },
359 fragment: Some(FragmentState {
360 shader: self.deferred_lighting_shader.clone(),
361 shader_defs,
362 targets: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Some(ColorTargetState {
format: key.target_format(),
blend: None,
write_mask: ColorWrites::ALL,
})]))vec![Some(ColorTargetState {
363 format: key.target_format(),
364 blend: None,
365 write_mask: ColorWrites::ALL,
366 })],
367 ..default()
368 }),
369 depth_stencil: Some(DepthStencilState {
370 format: DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
371 depth_write_enabled: Some(false),
372 depth_compare: Some(CompareFunction::Equal),
373 stencil: StencilState {
374 front: StencilFaceState::IGNORE,
375 back: StencilFaceState::IGNORE,
376 read_mask: 0,
377 write_mask: 0,
378 },
379 bias: DepthBiasState {
380 constant: 0,
381 slope_scale: 0.0,
382 clamp: 0.0,
383 },
384 }),
385 ..default()
386 }
387 }
388}
389
390pub fn init_deferred_lighting_layout(
391 mut commands: Commands,
392 mesh_pipeline: Res<MeshPipeline>,
393 asset_server: Res<AssetServer>,
394) {
395 let layout = BindGroupLayoutDescriptor::new(
396 "deferred_lighting_layout",
397 &BindGroupLayoutEntries::single(
398 ShaderStages::VERTEX_FRAGMENT,
399 uniform_buffer::<PbrDeferredLightingDepthId>(false),
400 ),
401 );
402 commands.insert_resource(DeferredLightingLayout {
403 mesh_pipeline: mesh_pipeline.clone(),
404 bind_group_layout_2: layout,
405 deferred_lighting_shader: {
let (path, asset_server) =
{
let path =
{
{
let crate_name =
"bevy_pbr::deferred".split(':').next().unwrap();
::bevy_asset::io::embedded::_embedded_asset_path(crate_name,
"src".as_ref(), "src/deferred/mod.rs".as_ref(),
"deferred_lighting.wesl".as_ref())
}
};
let path =
::bevy_asset::AssetPath::from_path_buf(path).with_source("embedded");
let asset_server =
::bevy_asset::io::embedded::GetAssetServer::get_asset_server(asset_server.as_ref());
(path, asset_server)
};
asset_server.load(path)
}load_embedded_asset!(
406 asset_server.as_ref(),
407 "deferred_lighting.wesl"
408 ),
409 });
410}
411
412pub fn insert_deferred_lighting_pass_id_component(
413 mut commands: Commands,
414 views: Query<Entity, (With<DeferredPrepass>, Without<PbrDeferredLightingDepthId>)>,
415) {
416 for entity in views.iter() {
417 commands
418 .entity(entity)
419 .insert(PbrDeferredLightingDepthId::default());
420 }
421}
422
423pub fn prepare_deferred_lighting_pipelines(
424 mut commands: Commands,
425 pipeline_cache: Res<PipelineCache>,
426 view_key_cache: Res<ViewKeyCache>,
427 mut pipelines: ResMut<SpecializedRenderPipelines<DeferredLightingLayout>>,
428 deferred_lighting_layout: Res<DeferredLightingLayout>,
429 cameras: Query<
430 (
431 Entity,
432 &ExtractedView,
433 Has<DeferredPrepass>,
434 Has<SkipDeferredLighting>,
435 ),
436 With<ExtractedCamera>,
437 >,
438) {
439 for (entity, view, deferred_prepass, skip_deferred_lighting) in &cameras {
440 if !deferred_prepass || skip_deferred_lighting {
444 commands.entity(entity).remove::<DeferredLightingPipeline>();
445 continue;
446 }
447
448 let Some(view_key) = view_key_cache.get(&view.retained_view_entity) else {
452 continue;
453 };
454
455 let pipeline_id =
456 pipelines.specialize(&pipeline_cache, &deferred_lighting_layout, *view_key);
457
458 commands
459 .entity(entity)
460 .insert(DeferredLightingPipeline { pipeline_id });
461 }
462}
463
464#[derive(impl bevy_ecs::component::Component for SkipDeferredLighting where
Self: ::core::marker::Send + ::core::marker::Sync + 'static {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(_requiree:
bevy_ecs::component::ComponentId,
required_components:
&mut bevy_ecs::component::RequiredComponentsRegistrator) {}
fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
use bevy_ecs::component::{
DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
};
(&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
}
fn relationship_accessor()
->
::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
::core::option::Option::None
}
}Component, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SkipDeferredLighting { }
#[automatically_derived]
impl ::core::clone::Clone for SkipDeferredLighting {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SkipDeferredLighting { }Copy, #[automatically_derived]
impl ::core::default::Default for SkipDeferredLighting {
#[inline]
fn default() -> Self { Self }
}Default)]
473pub struct SkipDeferredLighting;