Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 47 additions & 137 deletions crates/bevy_pbr/src/deferred/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{
DistanceFog, ExtractedAtmosphere, MeshPipeline, MeshPipelineKey, MeshPipelineSystems,
MeshViewBindGroup, RenderViewLightProbes, ScreenSpaceAmbientOcclusion,
ScreenSpaceReflectionsUniform, ScreenSpaceTransmission, TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE, MeshPipeline, MeshPipelineKey,
MeshPipelineSystems, MeshViewBindGroup, ViewKeyCache, TONEMAPPING_LUT_SAMPLER_BINDING_INDEX,
TONEMAPPING_LUT_TEXTURE_BINDING_INDEX,
};
use bevy_app::prelude::*;
Expand All @@ -11,13 +10,10 @@ use bevy_core_pipeline::{
deferred::{
copy_lighting_id::DeferredLightingIdDepthTexture, DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT,
},
oit::OrderIndependentTransparencySettingsOffset,
prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},
prepass::DeferredPrepass,
schedule::{Core3d, Core3dSystems},
tonemapping::{DebandDither, Tonemapping},
};
use bevy_ecs::prelude::*;
use bevy_light::{EnvironmentMapLight, IrradianceVolume, ShadowFilteringMethod};
use bevy_render::{
camera::ExtractedCamera,
extract_component::{
Expand Down Expand Up @@ -257,7 +253,7 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
shader_defs.push("ENVIRONMENT_MAP".into());
}

if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) {
if key.contains(MeshPipelineKey::IRRADIANCE_VOLUME) && IRRADIANCE_VOLUMES_ARE_USABLE {
shader_defs.push("IRRADIANCE_VOLUME".into());
}

Expand All @@ -277,6 +273,10 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
shader_defs.push("SCREEN_SPACE_REFLECTIONS".into());
}

if key.contains(MeshPipelineKey::CONTACT_SHADOWS) {
shader_defs.push("CONTACT_SHADOWS".into());
}

if key.contains(MeshPipelineKey::HAS_PREVIOUS_SKIN) {
shader_defs.push("HAS_PREVIOUS_SKIN".into());
}
Expand Down Expand Up @@ -310,9 +310,33 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
}

if IRRADIANCE_VOLUMES_ARE_USABLE {
shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
}

if self.mesh_pipeline.clustered_decals_are_usable {
shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
if cfg!(feature = "pbr_light_textures") {
shader_defs.push("LIGHT_TEXTURES".into());
}
}

#[cfg(feature = "experimental_pbr_pcss")]
shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into());

#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into());

if cfg!(feature = "bluenoise_texture") {
shader_defs.push("BLUE_NOISE_TEXTURE".into());
}
if cfg!(feature = "dfg_lut") {
shader_defs.push("DFG_LUT".into());
}
if cfg!(feature = "area_light_luts") {
shader_defs.push("AREA_LIGHT_LUTS".into());
}

let layout = self.mesh_pipeline.get_view_layout(key.into());
RenderPipelineDescriptor {
label: Some("deferred_lighting_pipeline".into()),
Expand Down Expand Up @@ -393,51 +417,20 @@ pub fn insert_deferred_lighting_pass_id_component(
pub fn prepare_deferred_lighting_pipelines(
mut commands: Commands,
pipeline_cache: Res<PipelineCache>,
view_key_cache: Res<ViewKeyCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<DeferredLightingLayout>>,
deferred_lighting_layout: Res<DeferredLightingLayout>,
cameras: Query<(
Entity,
&ExtractedCamera,
&ExtractedView,
Option<&Tonemapping>,
Option<&DebandDither>,
Option<&ShadowFilteringMethod>,
cameras: Query<
(
Has<ScreenSpaceAmbientOcclusion>,
Has<ScreenSpaceReflectionsUniform>,
Has<DistanceFog>,
),
(
Has<NormalPrepass>,
Has<DepthPrepass>,
Has<MotionVectorPrepass>,
Entity,
&ExtractedView,
Has<DeferredPrepass>,
Has<SkipDeferredLighting>,
),
Has<RenderViewLightProbes<EnvironmentMapLight>>,
Has<RenderViewLightProbes<IrradianceVolume>>,
Option<&ScreenSpaceTransmission>,
Has<OrderIndependentTransparencySettingsOffset>,
Has<SkipDeferredLighting>,
Has<ExtractedAtmosphere>,
)>,
With<ExtractedCamera>,
>,
) {
for (
entity,
camera,
view,
tonemapping,
dither,
shadow_filter_method,
(ssao, ssr, distance_fog),
(normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass),
has_environment_maps,
has_irradiance_volumes,
transmission,
has_oit,
skip_deferred_lighting,
has_atmosphere,
) in &cameras
{
for (entity, view, deferred_prepass, skip_deferred_lighting) in &cameras {
// If there is no deferred prepass or we want to skip the deferred lighting pass,
// remove the old pipeline if there was one. This handles the case in which a
// view using deferred stops using it.
Expand All @@ -446,98 +439,15 @@ pub fn prepare_deferred_lighting_pipelines(
continue;
}

let mut view_key = MeshPipelineKey::from_target_format(view.target_format);

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;
}

if has_atmosphere {
view_key |= MeshPipelineKey::ATMOSPHERE;
}

if let Some(transmission) = transmission {
view_key |= transmission.quality.pipeline_key();
}

if has_oit {
view_key |= MeshPipelineKey::OIT_ENABLED;
}

if view.invert_culling {
view_key |= MeshPipelineKey::INVERT_CULLING;
}

// Always true, since we're in the deferred lighting pipeline
view_key |= MeshPipelineKey::DEFERRED_PREPASS;

if !camera.hdr {
if let Some(tonemapping) = tonemapping {
view_key |= MeshPipelineKey::TONEMAP_IN_SHADER;
view_key |= match tonemapping {
Tonemapping::None => MeshPipelineKey::TONEMAP_METHOD_NONE,
Tonemapping::Reinhard => MeshPipelineKey::TONEMAP_METHOD_REINHARD,
Tonemapping::ReinhardLuminance => {
MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE
}
Tonemapping::AcesFitted => MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED,
Tonemapping::AgX => MeshPipelineKey::TONEMAP_METHOD_AGX,
Tonemapping::SomewhatBoringDisplayTransform => {
MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
}
Tonemapping::TonyMcMapface => MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE,
Tonemapping::BlenderFilmic => MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC,
Tonemapping::KhronosPbrNeutral => MeshPipelineKey::TONEMAP_METHOD_PBR_NEUTRAL,
};
}
if let Some(DebandDither::Enabled) = dither {
view_key |= MeshPipelineKey::DEBAND_DITHER;
}
}

if ssao {
view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION;
}
if ssr {
view_key |= MeshPipelineKey::SCREEN_SPACE_REFLECTIONS;
}
if distance_fog {
view_key |= MeshPipelineKey::DISTANCE_FOG;
}

// We don't need to check to see whether the environment map is loaded
// because [`gather_light_probes`] already checked that for us before
// adding the [`RenderViewEnvironmentMaps`] component.
if has_environment_maps {
view_key |= MeshPipelineKey::ENVIRONMENT_MAP;
}

if has_irradiance_volumes {
view_key |= MeshPipelineKey::IRRADIANCE_VOLUME;
}

match shadow_filter_method.unwrap_or(&ShadowFilteringMethod::default()) {
ShadowFilteringMethod::Hardware2x2 => {
view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_HARDWARE_2X2;
}
ShadowFilteringMethod::Gaussian => {
view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_GAUSSIAN;
}
ShadowFilteringMethod::Temporal => {
view_key |= MeshPipelineKey::SHADOW_FILTER_METHOD_TEMPORAL;
}
}
// The deferred lighting pass runs the same lighting code as the forward
// pass, so it must be specialized with the same view key. Reusing
// [`ViewKeyCache`] keeps the two in sync automatically.
let Some(view_key) = view_key_cache.get(&view.retained_view_entity) else {
continue;
};

let pipeline_id =
pipelines.specialize(&pipeline_cache, &deferred_lighting_layout, view_key);
pipelines.specialize(&pipeline_cache, &deferred_lighting_layout, *view_key);

commands
.entity(entity)
Expand Down