diff --git a/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl b/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl index d9c2f3e4e08f8a..acd898a6b32e06 100644 --- a/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl +++ b/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl @@ -50,7 +50,9 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { #ifdef WEBGL2 frag_coord.z = deferred_types::unpack_unorm3x4_plus_unorm_20_(deferred_data.b).w; #else +#ifdef DEPTH_PREPASS frag_coord.z = bevy_pbr::prepass_utils::prepass_depth(in.position, 0u); +#endif #endif var pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, deferred_data); diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index 564c973eef460a..568be134be18a8 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -8,7 +8,7 @@ use bevy_core_pipeline::{ copy_lighting_id::DeferredLightingIdDepthTexture, DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT, }, prelude::{Camera3d, ClearColor}, - prepass::DeferredPrepass, + prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, tonemapping::{DebandDither, Tonemapping}, }; use bevy_ecs::{prelude::*, query::QueryItem}; @@ -258,6 +258,9 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { let mut shader_defs = Vec::new(); + // Let the shader code know that it's running in a deferred pipeline. + shader_defs.push("DEFERRED_LIGHTING_PIPELINE".into()); + #[cfg(all(feature = "webgl", target_arch = "wasm32"))] shader_defs.push("WEBGL2".into()); @@ -298,6 +301,21 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { shader_defs.push("ENVIRONMENT_MAP".into()); } + if key.contains(MeshPipelineKey::NORMAL_PREPASS) { + shader_defs.push("NORMAL_PREPASS".into()); + } + + if key.contains(MeshPipelineKey::DEPTH_PREPASS) { + shader_defs.push("DEPTH_PREPASS".into()); + } + + if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) { + shader_defs.push("MOTION_VECTOR_PREPASS".into()); + } + + // Always true, since we're in the deferred lighting pipeline + shader_defs.push("DEFERRED_PREPASS".into()); + let shadow_filter_method = key.intersection(MeshPipelineKey::SHADOW_FILTER_METHOD_RESERVED_BITS); if shadow_filter_method == MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2 { @@ -408,14 +426,44 @@ pub fn prepare_deferred_lighting_pipelines( Option<&EnvironmentMapLight>, Option<&ShadowFilteringMethod>, Option<&ScreenSpaceAmbientOcclusionSettings>, + ( + Has, + Has, + Has, + ), ), With, >, images: Res>, ) { - for (entity, view, tonemapping, dither, environment_map, shadow_filter_method, ssao) in &views { + for ( + entity, + view, + tonemapping, + dither, + environment_map, + shadow_filter_method, + ssao, + (normal_prepass, depth_prepass, motion_vector_prepass), + ) in &views + { let mut view_key = MeshPipelineKey::from_hdr(view.hdr); + if normal_prepass { + view_key |= MeshPipelineKey::NORMAL_PREPASS; + } + + if depth_prepass { + view_key |= MeshPipelineKey::DEPTH_PREPASS; + } + + if motion_vector_prepass { + view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS; + } + + // Always true, since we're in the deferred lighting pipeline + view_key |= MeshPipelineKey::DEFERRED_PREPASS; + if !view.hdr { if let Some(tonemapping) = tonemapping { view_key |= MeshPipelineKey::TONEMAP_IN_SHADER; diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 4e1ded19b7750d..490083bae5a0a3 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -8,7 +8,7 @@ use bevy_asset::{Asset, AssetApp, AssetEvent, AssetId, AssetServer, Assets, Hand use bevy_core_pipeline::{ core_3d::{AlphaMask3d, Opaque3d, Transparent3d}, experimental::taa::TemporalAntiAliasSettings, - prepass::{DeferredPrepass, NormalPrepass}, + prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, tonemapping::{DebandDither, Tonemapping}, }; use bevy_derive::{Deref, DerefMut}; @@ -450,8 +450,12 @@ pub fn queue_material_meshes( Option<&EnvironmentMapLight>, Option<&ShadowFilteringMethod>, Option<&ScreenSpaceAmbientOcclusionSettings>, - Option<&NormalPrepass>, - Option<&DeferredPrepass>, + ( + Has, + Has, + Has, + Has, + ), Option<&TemporalAntiAliasSettings>, &mut RenderPhase, &mut RenderPhase, @@ -468,8 +472,7 @@ pub fn queue_material_meshes( environment_map, shadow_filter_method, ssao, - normal_prepass, - deferred_prepass, + (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass), taa_settings, mut opaque_phase, mut alpha_mask_phase, @@ -483,11 +486,19 @@ pub fn queue_material_meshes( let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples()) | MeshPipelineKey::from_hdr(view.hdr); - if normal_prepass.is_some() { + if normal_prepass { view_key |= MeshPipelineKey::NORMAL_PREPASS; } - if deferred_prepass.is_some() { + if depth_prepass { + view_key |= MeshPipelineKey::DEPTH_PREPASS; + } + + if motion_vector_prepass { + view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS; + } + + if deferred_prepass { view_key |= MeshPipelineKey::DEFERRED_PREPASS; } @@ -554,10 +565,6 @@ pub fn queue_material_meshes( } mesh_key |= alpha_mode_pipeline_key(material.properties.alpha_mode); - if deferred_prepass.is_some() && !forward { - mesh_key |= MeshPipelineKey::DEFERRED_PREPASS; - } - let pipeline_id = pipelines.specialize( &pipeline_cache, &material_pipeline, diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 53e26506121a0b..6e89575bb6b0a4 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -378,6 +378,11 @@ where let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); + // Let the shader code know that it's running in a prepass pipeline. + // (PBR code will use this to detect that it's running in deferred mode, + // since that's the only time it gets called from a prepass pipeline.) + shader_defs.push("PREPASS_PIPELINE".into()); + // NOTE: Eventually, it would be nice to only add this when the shaders are overloaded by the Material. // The main limitation right now is that bind group order is hardcoded in shaders. bind_group_layouts.insert(1, self.material_layout.clone()); diff --git a/crates/bevy_pbr/src/prepass/prepass_utils.wgsl b/crates/bevy_pbr/src/prepass/prepass_utils.wgsl index f36e373684934b..2d8ec615076afc 100644 --- a/crates/bevy_pbr/src/prepass/prepass_utils.wgsl +++ b/crates/bevy_pbr/src/prepass/prepass_utils.wgsl @@ -2,7 +2,7 @@ #import bevy_pbr::mesh_view_bindings as view_bindings -#ifndef DEPTH_PREPASS +#ifdef DEPTH_PREPASS fn prepass_depth(frag_coord: vec4, sample_index: u32) -> f32 { #ifdef MULTISAMPLED let depth_sample = textureLoad(view_bindings::depth_prepass_texture, vec2(frag_coord.xy), i32(sample_index)); @@ -13,7 +13,7 @@ fn prepass_depth(frag_coord: vec4, sample_index: u32) -> f32 { } #endif // DEPTH_PREPASS -#ifndef NORMAL_PREPASS +#ifdef NORMAL_PREPASS fn prepass_normal(frag_coord: vec4, sample_index: u32) -> vec3 { #ifdef MULTISAMPLED let normal_sample = textureLoad(view_bindings::normal_prepass_texture, vec2(frag_coord.xy), i32(sample_index)); @@ -24,7 +24,7 @@ fn prepass_normal(frag_coord: vec4, sample_index: u32) -> vec3 { } #endif // NORMAL_PREPASS -#ifndef MOTION_VECTOR_PREPASS +#ifdef MOTION_VECTOR_PREPASS fn prepass_motion_vector(frag_coord: vec4, sample_index: u32) -> vec2 { #ifdef MULTISAMPLED let motion_vector_sample = textureLoad(view_bindings::motion_vector_prepass_texture, vec2(frag_coord.xy), i32(sample_index)); diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 1675997707efcb..8d4fbb7b2f5450 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -772,6 +772,9 @@ impl SpecializedMeshPipeline for MeshPipeline { let mut shader_defs = Vec::new(); let mut vertex_attributes = Vec::new(); + // Let the shader code know that it's running in a mesh pipeline. + shader_defs.push("MESH_PIPELINE".into()); + shader_defs.push("VERTEX_OUTPUT_INSTANCE_INDEX".into()); if layout.contains(Mesh::ATTRIBUTE_POSITION) { @@ -870,6 +873,22 @@ impl SpecializedMeshPipeline for MeshPipeline { is_opaque = true; } + if key.contains(MeshPipelineKey::NORMAL_PREPASS) { + shader_defs.push("NORMAL_PREPASS".into()); + } + + if key.contains(MeshPipelineKey::DEPTH_PREPASS) { + shader_defs.push("DEPTH_PREPASS".into()); + } + + if key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) { + shader_defs.push("MOTION_VECTOR_PREPASS".into()); + } + + if key.contains(MeshPipelineKey::DEFERRED_PREPASS) { + shader_defs.push("DEFERRED_PREPASS".into()); + } + if key.contains(MeshPipelineKey::NORMAL_PREPASS) && key.msaa_samples() == 1 && is_opaque { shader_defs.push("LOAD_PREPASS_NORMALS".into()); } diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index 77057f27558910..ba7aca60ba0928 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -16,13 +16,13 @@ #import bevy_pbr::gtao_utils gtao_multibounce #endif -#ifdef DEFERRED_PREPASS +#ifdef PREPASS_PIPELINE #import bevy_pbr::pbr_deferred_functions deferred_gbuffer_from_pbr_input #import bevy_pbr::pbr_prepass_functions calculate_motion_vector #import bevy_pbr::prepass_io VertexOutput, FragmentOutput -#else // DEFERRED_PREPASS +#else // PREPASS_PIPELINE #import bevy_pbr::forward_io VertexOutput, FragmentOutput -#endif // DEFERRED_PREPASS +#endif // PREPASS_PIPELINE #ifdef MOTION_VECTOR_PREPASS @group(0) @binding(2) @@ -159,7 +159,7 @@ fn fragment( pbr_input.V = V; } else { // if UNLIT_BIT != 0 -#ifdef DEFERRED_PREPASS +#ifdef PREPASS_PIPELINE // in deferred mode, we need to fill some of the pbr input data even for unlit materials // to pass through the gbuffer to the deferred lighting shader pbr_input = pbr_types::pbr_input_new(); @@ -179,7 +179,7 @@ fn fragment( // generate output // --------------- -#ifdef DEFERRED_PREPASS +#ifdef PREPASS_PIPELINE // write the gbuffer out.deferred = deferred_gbuffer_from_pbr_input(pbr_input); out.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id; @@ -190,7 +190,7 @@ fn fragment( out.motion_vector = calculate_motion_vector(in.world_position, in.previous_world_position); #endif // MOTION_VECTOR_PREPASS -#else // DEFERRED_PREPASS +#else // PREPASS_PIPELINE // in forward mode, we calculate the lit color immediately, and then apply some post-lighting effects here. // in deferred mode the lit color and these effects will be calculated in the deferred lighting shader @@ -222,7 +222,7 @@ fn fragment( // write the final pixel color out.color = output_color; -#endif //DEFERRED_PREPASS +#endif // PREPASS_PIPELINE return out; }