From 56aa90240e9c03d6c3393c20c2d26fa04a11134c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 22 Jan 2025 21:24:54 -0800 Subject: [PATCH] Only include distance fog in the PBR shader if the view uses it. (#17495) Right now, we always include distance fog in the shader, which is unfortunate as it's complex code and is rare. This commit changes it to be a `#define` instead. I haven't confirmed that removing distance fog meaningfully reduces VGPR usage, but it can't hurt. --- crates/bevy_pbr/src/deferred/mod.rs | 13 +++++++++++-- crates/bevy_pbr/src/material.rs | 5 +++++ .../src/meshlet/material_pipeline_prepare.rs | 7 +++++-- crates/bevy_pbr/src/render/mesh.rs | 7 ++++++- crates/bevy_pbr/src/render/pbr_functions.wgsl | 6 +++++- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index 67271a916f..184249657a 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -6,7 +6,8 @@ use crate::{ TONEMAPPING_LUT_TEXTURE_BINDING_INDEX, }; use crate::{ - MeshPipelineKey, ShadowFilteringMethod, ViewFogUniformOffset, ViewLightsUniformOffset, + DistanceFog, MeshPipelineKey, ShadowFilteringMethod, ViewFogUniformOffset, + ViewLightsUniformOffset, }; use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, Handle}; @@ -328,6 +329,10 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { shader_defs.push("HAS_PREVIOUS_MORPH".into()); } + if key.contains(MeshPipelineKey::DISTANCE_FOG) { + shader_defs.push("DISTANCE_FOG".into()); + } + // Always true, since we're in the deferred lighting pipeline shader_defs.push("DEFERRED_PREPASS".into()); @@ -437,6 +442,7 @@ pub fn prepare_deferred_lighting_pipelines( ( Has, Has, + Has, ), ( Has, @@ -455,7 +461,7 @@ pub fn prepare_deferred_lighting_pipelines( tonemapping, dither, shadow_filter_method, - (ssao, ssr), + (ssao, ssr, distance_fog), (normal_prepass, depth_prepass, motion_vector_prepass), has_environment_maps, has_irradiance_volumes, @@ -507,6 +513,9 @@ pub fn prepare_deferred_lighting_pipelines( 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 diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 112c1cb368..df7fb2142d 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -702,6 +702,7 @@ pub fn queue_material_meshes( Option<&Camera3d>, Has, Option<&Projection>, + Has, ( Has>, Has>, @@ -723,6 +724,7 @@ pub fn queue_material_meshes( camera_3d, temporal_jitter, projection, + distance_fog, (has_environment_maps, has_irradiance_volumes), has_oit, ) in &views @@ -814,6 +816,9 @@ pub fn queue_material_meshes( if ssao { view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION; } + if distance_fog { + view_key |= MeshPipelineKey::DISTANCE_FOG; + } if let Some(camera_3d) = camera_3d { view_key |= screen_space_specular_transmission_pipeline_key( camera_3d.screen_space_specular_transmission_quality, diff --git a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs index 2a44e5934c..7ce19cc50e 100644 --- a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs +++ b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs @@ -48,7 +48,7 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( Option<&Tonemapping>, Option<&DebandDither>, Option<&ShadowFilteringMethod>, - Has, + (Has, Has), ( Has, Has, @@ -73,7 +73,7 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( tonemapping, dither, shadow_filter_method, - ssao, + (ssao, distance_fog), (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass), temporal_jitter, projection, @@ -142,6 +142,9 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( if ssao { view_key |= MeshPipelineKey::SCREEN_SPACE_AMBIENT_OCCLUSION; } + if distance_fog { + view_key |= MeshPipelineKey::DISTANCE_FOG; + } view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList); diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index f5e79ae169..0ce11ec2ff 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1809,7 +1809,8 @@ bitflags::bitflags! { const HAS_PREVIOUS_SKIN = 1 << 18; const HAS_PREVIOUS_MORPH = 1 << 19; const OIT_ENABLED = 1 << 20; - const LAST_FLAG = Self::OIT_ENABLED.bits(); + const DISTANCE_FOG = 1 << 21; + const LAST_FLAG = Self::DISTANCE_FOG.bits(); // Bitfields const MSAA_RESERVED_BITS = Self::MSAA_MASK_BITS << Self::MSAA_SHIFT_BITS; @@ -2268,6 +2269,10 @@ impl SpecializedMeshPipeline for MeshPipeline { shader_defs.push("VISIBILITY_RANGE_DITHER".into()); } + if key.contains(MeshPipelineKey::DISTANCE_FOG) { + shader_defs.push("DISTANCE_FOG".into()); + } + if self.binding_arrays_are_usable { shader_defs.push("MULTIPLE_LIGHT_PROBES_IN_ARRAY".into()); shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into()); diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 161b59be31..04b52f8780 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -759,6 +759,7 @@ fn apply_pbr_lighting( } #endif // PREPASS_FRAGMENT +#ifdef DISTANCE_FOG fn apply_fog(fog_params: mesh_view_types::Fog, input_color: vec4, fragment_world_position: vec3, view_world_position: vec3) -> vec4 { let view_to_world = fragment_world_position.xyz - view_world_position.xyz; @@ -796,6 +797,7 @@ fn apply_fog(fog_params: mesh_view_types::Fog, input_color: vec4, fragment_ return input_color; } } +#endif // DISTANCE_FOG #ifdef PREMULTIPLY_ALPHA fn premultiply_alpha(standard_material_flags: u32, color: vec4) -> vec4 { @@ -857,10 +859,12 @@ fn main_pass_post_lighting_processing( ) -> vec4 { var output_color = input_color; +#ifdef DISTANCE_FOG // fog - if (view_bindings::fog.mode != mesh_view_types::FOG_MODE_OFF && (pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT) != 0u) { + if ((pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT) != 0u) { output_color = apply_fog(view_bindings::fog, output_color, pbr_input.world_position.xyz, view_bindings::view.world_position.xyz); } +#endif // DISTANCE_FOG #ifdef TONEMAP_IN_SHADER output_color = tone_mapping(output_color, view_bindings::view.color_grading);