From e6fbcb786bdbe93868b4692193b7f2dd8e7c5df3 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Wed, 13 Nov 2024 23:39:26 -0800 Subject: [PATCH] Make PCSS experimental (#16382) # Objective PCSS still has some fundamental issues (#16155). We should resolve them before "releasing" the feature. ## Solution 1. Rename the already-optional `pbr_pcss` cargo feature to `experimental_pbr_pcss` to better communicate its state to developers. 2. Adjust the description of the `experimental_pbr_pcss` cargo feature to better communicate its state to developers. 3. Gate PCSS-related light component fields behind that cargo feature, to prevent surfacing them to developers by default. --- Cargo.toml | 4 +-- crates/bevy_internal/Cargo.toml | 2 +- crates/bevy_pbr/Cargo.toml | 2 +- .../bevy_pbr/src/light/directional_light.rs | 4 ++- crates/bevy_pbr/src/light/point_light.rs | 4 ++- crates/bevy_pbr/src/light/spot_light.rs | 4 ++- crates/bevy_pbr/src/render/light.rs | 35 ++++++++++++------- crates/bevy_pbr/src/render/mesh.rs | 2 +- .../bevy_pbr/src/render/mesh_view_bindings.rs | 8 ++--- docs/cargo_features.md | 2 +- 10 files changed, 41 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6dbaf60c9c..1c79fba379 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -403,7 +403,7 @@ pbr_multi_layer_material_textures = [ pbr_anisotropy_texture = ["bevy_internal/pbr_anisotropy_texture"] # Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs -pbr_pcss = ["bevy_internal/pbr_pcss"] +experimental_pbr_pcss = ["bevy_internal/experimental_pbr_pcss"] # Enable some limitations to be able to use WebGL2. Please refer to the [WebGL2 and WebGPU](https://github.com/bevyengine/bevy/tree/latest/examples#webgl2-and-webgpu) section of the examples README for more information on how to run Wasm builds with WebGPU. webgl2 = ["bevy_internal/webgl"] @@ -3790,7 +3790,7 @@ wasm = true name = "pcss" path = "examples/3d/pcss.rs" doc-scrape-examples = true -required-features = ["pbr_pcss"] +required-features = ["experimental_pbr_pcss"] [package.metadata.example.pcss] name = "Percentage-closer soft shadows" diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index a467c8ef8f..7bdb93afb8 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -135,7 +135,7 @@ pbr_anisotropy_texture = [ ] # Percentage-closer soft shadows -pbr_pcss = ["bevy_pbr?/pbr_pcss"] +experimental_pbr_pcss = ["bevy_pbr?/experimental_pbr_pcss"] # Optimise for WebGL2 webgl = [ diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index d137167702..318c3b5051 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -14,7 +14,7 @@ webgpu = [] pbr_transmission_textures = [] pbr_multi_layer_material_textures = [] pbr_anisotropy_texture = [] -pbr_pcss = [] +experimental_pbr_pcss = [] shader_format_glsl = ["bevy_render/shader_format_glsl"] trace = ["bevy_render/trace"] ios_simulator = ["bevy_render/ios_simulator"] diff --git a/crates/bevy_pbr/src/light/directional_light.rs b/crates/bevy_pbr/src/light/directional_light.rs index 3bc8c49cd2..06c277aef7 100644 --- a/crates/bevy_pbr/src/light/directional_light.rs +++ b/crates/bevy_pbr/src/light/directional_light.rs @@ -95,6 +95,7 @@ pub struct DirectionalLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. + #[cfg(feature = "experimental_pbr_pcss")] pub soft_shadow_size: Option, /// A value that adjusts the tradeoff between self-shadowing artifacts and @@ -120,9 +121,10 @@ impl Default for DirectionalLight { color: Color::WHITE, illuminance: light_consts::lux::AMBIENT_DAYLIGHT, shadows_enabled: false, - soft_shadow_size: None, shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, + #[cfg(feature = "experimental_pbr_pcss")] + soft_shadow_size: None, } } } diff --git a/crates/bevy_pbr/src/light/point_light.rs b/crates/bevy_pbr/src/light/point_light.rs index a351913aab..ee08a57ba1 100644 --- a/crates/bevy_pbr/src/light/point_light.rs +++ b/crates/bevy_pbr/src/light/point_light.rs @@ -61,6 +61,7 @@ pub struct PointLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. + #[cfg(feature = "experimental_pbr_pcss")] pub soft_shadows_enabled: bool, /// A bias used when sampling shadow maps to avoid "shadow-acne", or false shadow occlusions @@ -95,10 +96,11 @@ impl Default for PointLight { range: 20.0, radius: 0.0, shadows_enabled: false, - soft_shadows_enabled: false, shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z, + #[cfg(feature = "experimental_pbr_pcss")] + soft_shadows_enabled: false, } } } diff --git a/crates/bevy_pbr/src/light/spot_light.rs b/crates/bevy_pbr/src/light/spot_light.rs index 9b78291b02..845d55e697 100644 --- a/crates/bevy_pbr/src/light/spot_light.rs +++ b/crates/bevy_pbr/src/light/spot_light.rs @@ -57,6 +57,7 @@ pub struct SpotLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. + #[cfg(feature = "experimental_pbr_pcss")] pub soft_shadows_enabled: bool, /// A value that adjusts the tradeoff between self-shadowing artifacts and @@ -115,12 +116,13 @@ impl Default for SpotLight { range: 20.0, radius: 0.0, shadows_enabled: false, - soft_shadows_enabled: false, shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z, inner_angle: 0.0, outer_angle: core::f32::consts::FRAC_PI_4, + #[cfg(feature = "experimental_pbr_pcss")] + soft_shadows_enabled: false, } } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index bd0248789d..ccfe397ab3 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -41,12 +41,12 @@ pub struct ExtractedPointLight { pub radius: f32, pub transform: GlobalTransform, pub shadows_enabled: bool, - pub soft_shadows_enabled: bool, pub shadow_depth_bias: f32, pub shadow_normal_bias: f32, pub shadow_map_near_z: f32, pub spot_light_angles: Option<(f32, f32)>, pub volumetric: bool, + pub soft_shadows_enabled: bool, } #[derive(Component, Debug)] @@ -56,13 +56,13 @@ pub struct ExtractedDirectionalLight { pub transform: GlobalTransform, pub shadows_enabled: bool, pub volumetric: bool, - pub soft_shadow_size: Option, pub shadow_depth_bias: f32, pub shadow_normal_bias: f32, pub cascade_shadow_config: CascadeShadowConfig, pub cascades: EntityHashMap>, pub frusta: EntityHashMap>, pub render_layers: RenderLayers, + pub soft_shadow_size: Option, } // NOTE: These must match the bit flags in bevy_pbr/src/render/mesh_view_types.wgsl! @@ -147,10 +147,10 @@ pub const MAX_CASCADES_PER_LIGHT: usize = 1; #[derive(Resource, Clone)] pub struct ShadowSamplers { pub point_light_comparison_sampler: Sampler, - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] pub point_light_linear_sampler: Sampler, pub directional_light_comparison_sampler: Sampler, - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] pub directional_light_linear_sampler: Sampler, } @@ -174,7 +174,7 @@ impl FromWorld for ShadowSamplers { compare: Some(CompareFunction::GreaterEqual), ..base_sampler_descriptor }), - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] point_light_linear_sampler: render_device.create_sampler(&base_sampler_descriptor), directional_light_comparison_sampler: render_device.create_sampler( &SamplerDescriptor { @@ -182,7 +182,7 @@ impl FromWorld for ShadowSamplers { ..base_sampler_descriptor }, ), - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] directional_light_linear_sampler: render_device .create_sampler(&base_sampler_descriptor), } @@ -291,7 +291,6 @@ pub fn extract_lights( radius: point_light.radius, transform: *transform, shadows_enabled: point_light.shadows_enabled, - soft_shadows_enabled: point_light.soft_shadows_enabled, shadow_depth_bias: point_light.shadow_depth_bias, // The factor of SQRT_2 is for the worst-case diagonal offset shadow_normal_bias: point_light.shadow_normal_bias @@ -300,6 +299,10 @@ pub fn extract_lights( shadow_map_near_z: point_light.shadow_map_near_z, spot_light_angles: None, volumetric: volumetric_light.is_some(), + #[cfg(feature = "experimental_pbr_pcss")] + soft_shadows_enabled: point_light.soft_shadows_enabled, + #[cfg(not(feature = "experimental_pbr_pcss"))] + soft_shadows_enabled: false, }; point_lights_values.push(( render_entity, @@ -350,7 +353,6 @@ pub fn extract_lights( radius: spot_light.radius, transform: *transform, shadows_enabled: spot_light.shadows_enabled, - soft_shadows_enabled: spot_light.soft_shadows_enabled, shadow_depth_bias: spot_light.shadow_depth_bias, // The factor of SQRT_2 is for the worst-case diagonal offset shadow_normal_bias: spot_light.shadow_normal_bias @@ -359,6 +361,10 @@ pub fn extract_lights( shadow_map_near_z: spot_light.shadow_map_near_z, spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), volumetric: volumetric_light.is_some(), + #[cfg(feature = "experimental_pbr_pcss")] + soft_shadows_enabled: spot_light.soft_shadows_enabled, + #[cfg(not(feature = "experimental_pbr_pcss"))] + soft_shadows_enabled: false, }, render_visible_entities, *frustum, @@ -430,7 +436,10 @@ pub fn extract_lights( illuminance: directional_light.illuminance, transform: *transform, volumetric: volumetric_light.is_some(), + #[cfg(feature = "experimental_pbr_pcss")] soft_shadow_size: directional_light.soft_shadow_size, + #[cfg(not(feature = "experimental_pbr_pcss"))] + soft_shadow_size: None, shadows_enabled: directional_light.shadows_enabled, shadow_depth_bias: directional_light.shadow_depth_bias, // The factor of SQRT_2 is for the worst-case diagonal offset @@ -911,17 +920,17 @@ pub fn prepare_lights( .extend(1.0 / (light.range * light.range)), position_radius: light.transform.translation().extend(light.radius), flags: flags.bits(), - soft_shadow_size: if light.soft_shadows_enabled { - light.radius - } else { - 0.0 - }, shadow_depth_bias: light.shadow_depth_bias, shadow_normal_bias: light.shadow_normal_bias, shadow_map_near_z: light.shadow_map_near_z, spot_light_tan_angle, pad_a: 0.0, pad_b: 0.0, + soft_shadow_size: if light.soft_shadows_enabled { + light.radius + } else { + 0.0 + }, }); global_light_meta.entity_to_index.insert(entity, index); } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 06a1de09e2..e8adff671b 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1859,7 +1859,7 @@ impl SpecializedMeshPipeline for MeshPipeline { #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] shader_defs.push("WEBGL2".into()); - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into()); if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) { diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index bbf158564d..c3a723164e 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -228,7 +228,7 @@ fn layout_entries( // Point Shadow Texture Array Comparison Sampler (3, sampler(SamplerBindingType::Comparison)), // Point Shadow Texture Array Linear Sampler - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] (4, sampler(SamplerBindingType::Filtering)), // Directional Shadow Texture Array ( @@ -245,7 +245,7 @@ fn layout_entries( // Directional Shadow Texture Array Comparison Sampler (6, sampler(SamplerBindingType::Comparison)), // Directional Shadow Texture Array Linear Sampler - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] (7, sampler(SamplerBindingType::Filtering)), // PointLights ( @@ -580,11 +580,11 @@ pub fn prepare_mesh_view_bind_groups( (1, light_binding.clone()), (2, &shadow_bindings.point_light_depth_texture_view), (3, &shadow_samplers.point_light_comparison_sampler), - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] (4, &shadow_samplers.point_light_linear_sampler), (5, &shadow_bindings.directional_light_depth_texture_view), (6, &shadow_samplers.directional_light_comparison_sampler), - #[cfg(feature = "pbr_pcss")] + #[cfg(feature = "experimental_pbr_pcss")] (7, &shadow_samplers.directional_light_linear_sampler), (8, clusterable_objects_binding.clone()), ( diff --git a/docs/cargo_features.md b/docs/cargo_features.md index bb9d8d47ae..62f73f7c87 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -67,6 +67,7 @@ The default feature set enables most of the expected features of a game engine, |detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in| |dynamic_linking|Force dynamic linking, which improves iterative compile times| |embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading| +|experimental_pbr_pcss|Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs| |exr|EXR image format support| |ff|Farbfeld image format support| |file_watcher|Enables watching the filesystem for Bevy Asset hot-reloading| @@ -83,7 +84,6 @@ The default feature set enables most of the expected features of a game engine, |mp3|MP3 audio format support| |pbr_anisotropy_texture|Enable support for anisotropy texture in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs| |pbr_multi_layer_material_textures|Enable support for multi-layer material textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs| -|pbr_pcss|Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs| |pbr_transmission_textures|Enable support for transmission-related textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs| |pnm|PNM image format support, includes pam, pbm, pgm and ppm| |qoi|QOI image format support|