diff --git a/Cargo.toml b/Cargo.toml index 8ae8758696..a565240dee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -402,6 +402,9 @@ pbr_multi_layer_material_textures = [ # 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_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"] + # 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"] @@ -3786,6 +3789,7 @@ wasm = true name = "pcss" path = "examples/3d/pcss.rs" doc-scrape-examples = true +required-features = ["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 1a1930acc2..74267a4797 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -134,6 +134,9 @@ pbr_anisotropy_texture = [ "bevy_gltf?/pbr_anisotropy_texture", ] +# Percentage-closer soft shadows +pbr_pcss = ["bevy_pbr?/pbr_pcss"] + # Optimise for WebGL2 webgl = [ "bevy_core_pipeline?/webgl", diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 67552945fc..6f1d913c65 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -14,6 +14,7 @@ webgpu = [] pbr_transmission_textures = [] pbr_multi_layer_material_textures = [] pbr_anisotropy_texture = [] +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/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 4d64a6a306..bd0248789d 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -147,8 +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")] pub point_light_linear_sampler: Sampler, pub directional_light_comparison_sampler: Sampler, + #[cfg(feature = "pbr_pcss")] pub directional_light_linear_sampler: Sampler, } @@ -172,6 +174,7 @@ impl FromWorld for ShadowSamplers { compare: Some(CompareFunction::GreaterEqual), ..base_sampler_descriptor }), + #[cfg(feature = "pbr_pcss")] point_light_linear_sampler: render_device.create_sampler(&base_sampler_descriptor), directional_light_comparison_sampler: render_device.create_sampler( &SamplerDescriptor { @@ -179,6 +182,7 @@ impl FromWorld for ShadowSamplers { ..base_sampler_descriptor }, ), + #[cfg(feature = "pbr_pcss")] directional_light_linear_sampler: render_device .create_sampler(&base_sampler_descriptor), } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index af6621eb25..e996dbb8f0 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1858,6 +1858,9 @@ impl SpecializedMeshPipeline for MeshPipeline { #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] shader_defs.push("WEBGL2".into()); + #[cfg(feature = "pbr_pcss")] + shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into()); + if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) { shader_defs.push("TONEMAP_IN_SHADER".into()); shader_defs.push(ShaderDefVal::UInt( diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 8a55aecacc..9596eec729 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -227,6 +227,7 @@ fn layout_entries( // Point Shadow Texture Array Comparison Sampler (3, sampler(SamplerBindingType::Comparison)), // Point Shadow Texture Array Linear Sampler + #[cfg(feature = "pbr_pcss")] (4, sampler(SamplerBindingType::Filtering)), // Directional Shadow Texture Array ( @@ -243,6 +244,7 @@ fn layout_entries( // Directional Shadow Texture Array Comparison Sampler (6, sampler(SamplerBindingType::Comparison)), // Directional Shadow Texture Array Linear Sampler + #[cfg(feature = "pbr_pcss")] (7, sampler(SamplerBindingType::Filtering)), // PointLights ( @@ -574,9 +576,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")] (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")] (7, &shadow_samplers.directional_light_linear_sampler), (8, clusterable_objects_binding.clone()), ( diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl index e777b20358..e4f7f6ece0 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl @@ -14,14 +14,18 @@ @group(0) @binding(2) var point_shadow_textures: texture_depth_cube_array; #endif @group(0) @binding(3) var point_shadow_textures_comparison_sampler: sampler_comparison; +#ifdef PCSS_SAMPLERS_AVAILABLE @group(0) @binding(4) var point_shadow_textures_linear_sampler: sampler; +#endif // PCSS_SAMPLERS_AVAILABLE #ifdef NO_ARRAY_TEXTURES_SUPPORT @group(0) @binding(5) var directional_shadow_textures: texture_depth_2d; #else @group(0) @binding(5) var directional_shadow_textures: texture_depth_2d_array; #endif @group(0) @binding(6) var directional_shadow_textures_comparison_sampler: sampler_comparison; +#ifdef PCSS_SAMPLERS_AVAILABLE @group(0) @binding(7) var directional_shadow_textures_linear_sampler: sampler; +#endif // PCSS_SAMPLERS_AVAILABLE #if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3 @group(0) @binding(8) var clusterable_objects: types::ClusterableObjects; diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_pbr/src/render/shadow_sampling.wgsl index 0c546a37c6..22f2e28310 100644 --- a/crates/bevy_pbr/src/render/shadow_sampling.wgsl +++ b/crates/bevy_pbr/src/render/shadow_sampling.wgsl @@ -40,6 +40,8 @@ fn search_for_blockers_in_shadow_map_hardware( return vec2(0.0); #else // WEBGL2 +#ifdef PCSS_SAMPLERS_AVAILABLE + #ifdef NO_ARRAY_TEXTURES_SUPPORT let sampled_depth = textureSampleLevel( view_bindings::directional_shadow_textures, @@ -58,6 +60,10 @@ fn search_for_blockers_in_shadow_map_hardware( #endif // NO_ARRAY_TEXTURES_SUPPORT return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); +#else // PCSS_SAMPLERS_AVAILABLE + return vec2(0.0); +#endif // PCSS_SAMPLERS_AVAILABLE + #endif // WEBGL2 } @@ -340,6 +346,8 @@ fn search_for_blockers_in_shadow_cubemap_hardware( return vec2(0.0); #else // WEBGL2 +#ifdef PCSS_SAMPLERS_AVAILABLE + #ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT let sampled_depth = textureSample( view_bindings::point_shadow_textures, @@ -357,6 +365,10 @@ fn search_for_blockers_in_shadow_cubemap_hardware( return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); +#else // PCSS_SAMPLERS_AVAILABLE + return vec2(0.0); +#endif // PCSS_SAMPLERS_AVAILABLE + #endif // WEBGL2 } diff --git a/docs/cargo_features.md b/docs/cargo_features.md index b0434e72bd..bb9d8d47ae 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -83,6 +83,7 @@ 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| diff --git a/examples/shader/extended_material.rs b/examples/shader/extended_material.rs index c35f168e4c..3c5102db8a 100644 --- a/examples/shader/extended_material.rs +++ b/examples/shader/extended_material.rs @@ -32,7 +32,7 @@ fn setup( MeshMaterial3d(materials.add(ExtendedMaterial { base: StandardMaterial { base_color: RED.into(), - // can be used in forward or deferred mode. + // can be used in forward or deferred mode opaque_render_method: OpaqueRendererMethod::Auto, // in deferred mode, only the PbrInput can be modified (uvs, color and other material properties), // in forward mode, the output can also be modified after lighting is applied.