diff --git a/Cargo.toml b/Cargo.toml index 8a415e2fb346f..ae22fe0167171 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3467,17 +3467,6 @@ description = "Demonstrates animation masks" category = "Animation" wasm = true -[[example]] -name = "pcss" -path = "examples/3d/pcss.rs" -doc-scrape-examples = true - -[package.metadata.example.pcss] -name = "Percentage-closer soft shadows" -description = "Demonstrates percentage-closer soft shadows (PCSS)" -category = "3D Rendering" -wasm = false - [profile.wasm-release] inherits = "release" opt-level = "z" diff --git a/assets/environment_maps/sky_skybox.ktx2 b/assets/environment_maps/sky_skybox.ktx2 deleted file mode 100644 index d386497ac1efe..0000000000000 Binary files a/assets/environment_maps/sky_skybox.ktx2 and /dev/null differ diff --git a/assets/models/PalmTree/PalmTree.bin b/assets/models/PalmTree/PalmTree.bin deleted file mode 100644 index 614c4d29680bb..0000000000000 Binary files a/assets/models/PalmTree/PalmTree.bin and /dev/null differ diff --git a/assets/models/PalmTree/PalmTree.gltf b/assets/models/PalmTree/PalmTree.gltf deleted file mode 100644 index c4987e1ea67a1..0000000000000 --- a/assets/models/PalmTree/PalmTree.gltf +++ /dev/null @@ -1,1066 +0,0 @@ -{ - "asset":{ - "generator":"Khronos glTF Blender I/O v4.1.63", - "version":"2.0" - }, - "scene":0, - "scenes":[ - { - "name":"Scene", - "nodes":[ - 0, - 3, - 6, - 9, - 12, - 15, - 18, - 21, - 22, - 23 - ] - } - ], - "nodes":[ - { - "mesh":0, - "name":"B\u00e9zierCurve", - "rotation":[ - -0.6492608785629272, - 0.6492608189582825, - -0.28010788559913635, - 0.28010791540145874 - ], - "scale":[ - -1.5591872930526733, - -1.5591872930526733, - -1.5591872930526733 - ], - "translation":[ - 0.7588800191879272, - 1.8171958923339844, - -0.701636791229248 - ] - }, - { - "name":"B\u00e9zierCurve.001" - }, - { - "mesh":1, - "name":"Grid", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551956415176392, - 0.06293392181396484, - -0.1808854639530182 - ] - }, - { - "children":[ - 1, - 2 - ], - "name":"Empty", - "rotation":[ - 0, - -0.16959351301193237, - 0, - 0.9855141043663025 - ], - "translation":[ - 0.27010849118232727, - 3.3713648319244385, - -0.5507277250289917 - ] - }, - { - "name":"B\u00e9zierCurve.002" - }, - { - "mesh":2, - "name":"Grid.001", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551955819129944, - 0.06293395161628723, - -0.18088552355766296 - ] - }, - { - "children":[ - 4, - 5 - ], - "name":"Empty.001", - "rotation":[ - -0.1744275838136673, - -0.9500948786735535, - -0.04670312628149986, - 0.2543886601924896 - ], - "translation":[ - -0.32273390889167786, - 3.377293348312378, - -0.6218688488006592 - ] - }, - { - "name":"B\u00e9zierCurve.003" - }, - { - "mesh":3, - "name":"Grid.002", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551957011222839, - 0.06293392181396484, - -0.18088555335998535 - ] - }, - { - "children":[ - 7, - 8 - ], - "name":"Empty.002", - "rotation":[ - 0, - 0.9468244314193726, - 0, - 0.3217506408691406 - ], - "translation":[ - -0.10338221490383148, - 3.377293348312378, - -0.7404372692108154 - ] - }, - { - "name":"B\u00e9zierCurve.004" - }, - { - "mesh":4, - "name":"Grid.003", - "scale":[ - 0.7174922823905945, - 1, - 1 - ], - "translation":[ - 0.8551957011222839, - 0.0629342570900917, - -0.18088553845882416 - ] - }, - { - "children":[ - 10, - 11 - ], - "name":"Empty.003", - "rotation":[ - 0.039769601076841354, - -0.5909609794616699, - -0.054099712520837784, - 0.803900957107544 - ], - "translation":[ - -0.020384281873703003, - 3.377293348312378, - -0.3432328999042511 - ] - }, - { - "name":"B\u00e9zierCurve.005" - }, - { - "mesh":5, - "name":"Grid.004", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551955819129944, - 0.0629342794418335, - -0.18088550865650177 - ] - }, - { - "children":[ - 13, - 14 - ], - "name":"Empty.004", - "rotation":[ - 0.06433407217264175, - 0.6805833578109741, - 0.06868407875299454, - 0.7266016602516174 - ], - "translation":[ - 0.14561158418655396, - 3.377293348312378, - -0.633725643157959 - ] - }, - { - "name":"B\u00e9zierCurve.006" - }, - { - "mesh":6, - "name":"Grid.005", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551957607269287, - 0.06293407082557678, - -0.18088555335998535 - ] - }, - { - "children":[ - 16, - 17 - ], - "name":"Empty.005", - "rotation":[ - -0.027264947071671486, - 0.32132646441459656, - -0.08003053814172745, - 0.9431866407394409 - ], - "translation":[ - 0.14561158418655396, - 3.377293348312378, - -0.633725643157959 - ] - }, - { - "name":"B\u00e9zierCurve.007" - }, - { - "mesh":7, - "name":"Grid.006", - "scale":[ - 0.7174922227859497, - 1, - 1 - ], - "translation":[ - 0.8551956415176392, - 0.06293423473834991, - -0.18088550865650177 - ] - }, - { - "children":[ - 19, - 20 - ], - "name":"Empty.006", - "rotation":[ - 0.025538405403494835, - -0.8604785799980164, - -0.015095553360879421, - 0.5086221694946289 - ], - "translation":[ - -0.13840311765670776, - 3.38228178024292, - -0.48537585139274597 - ] - }, - { - "mesh":8, - "name":"Landscape", - "rotation":[ - 0, - -0.07845905423164368, - 0, - 0.9969173669815063 - ], - "scale":[ - 1.0773953199386597, - 1.0773954391479492, - 1.0773953199386597 - ], - "translation":[ - -1.4325428009033203, - 0.049118101596832275, - -17.66829490661621 - ] - }, - { - "mesh":9, - "name":"Landscape_plane", - "scale":[ - 6.12558650970459, - 6.12558650970459, - 6.12558650970459 - ] - } - ], - "materials":[ - { - "doubleSided":true, - "name":"Trunk", - "pbrMetallicRoughness":{ - "baseColorFactor":[ - 0.61811763048172, - 0.26356762647628784, - 0.11393062770366669, - 1 - ], - "metallicFactor":0, - "roughnessFactor":0.5 - } - }, - { - "doubleSided":true, - "name":"Leaves", - "pbrMetallicRoughness":{ - "baseColorFactor":[ - 0.2105390429496765, - 0.8000074625015259, - 0.14856106042861938, - 1 - ], - "metallicFactor":0, - "roughnessFactor":0.5 - } - }, - { - "doubleSided":true, - "name":"Material.001", - "pbrMetallicRoughness":{ - "baseColorFactor":[ - 1, - 0.9668273329734802, - 0.5682248473167419, - 1 - ], - "metallicFactor":0, - "roughnessFactor":0.5 - } - }, - { - "doubleSided":true, - "emissiveFactor":[ - 1, - 1, - 1 - ], - "emissiveTexture":{ - "index":0 - }, - "name":"Water", - "pbrMetallicRoughness":{ - "baseColorTexture":{ - "index":1 - }, - "metallicFactor":0, - "roughnessFactor":0.5 - } - } - ], - "meshes":[ - { - "name":"B\u00e9zierCurve", - "primitives":[ - { - "attributes":{ - "POSITION":0, - "NORMAL":1, - "TEXCOORD_0":2 - }, - "indices":3, - "material":0 - } - ] - }, - { - "name":"Grid", - "primitives":[ - { - "attributes":{ - "POSITION":4, - "NORMAL":5, - "TEXCOORD_0":6 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.001", - "primitives":[ - { - "attributes":{ - "POSITION":8, - "NORMAL":9, - "TEXCOORD_0":10 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.002", - "primitives":[ - { - "attributes":{ - "POSITION":11, - "NORMAL":12, - "TEXCOORD_0":13 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.003", - "primitives":[ - { - "attributes":{ - "POSITION":14, - "NORMAL":15, - "TEXCOORD_0":16 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.004", - "primitives":[ - { - "attributes":{ - "POSITION":17, - "NORMAL":18, - "TEXCOORD_0":19 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.005", - "primitives":[ - { - "attributes":{ - "POSITION":20, - "NORMAL":21, - "TEXCOORD_0":22 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Grid.006", - "primitives":[ - { - "attributes":{ - "POSITION":23, - "NORMAL":24, - "TEXCOORD_0":25 - }, - "indices":7, - "material":1 - } - ] - }, - { - "name":"Landscape.001", - "primitives":[ - { - "attributes":{ - "POSITION":26, - "NORMAL":27, - "TEXCOORD_0":28 - }, - "indices":29, - "material":2 - } - ] - }, - { - "name":"Landscape_plane", - "primitives":[ - { - "attributes":{ - "POSITION":30, - "NORMAL":31, - "TEXCOORD_0":32 - }, - "indices":33, - "material":3 - } - ] - } - ], - "textures":[ - { - "sampler":0, - "source":0 - }, - { - "sampler":0, - "source":0 - } - ], - "images":[ - { - "mimeType":"image/png", - "name":"StylizedWater", - "uri":"StylizedWater.png" - } - ], - "accessors":[ - { - "bufferView":0, - "componentType":5126, - "count":720, - "max":[ - 1.0449047088623047, - 0.10000000149011612, - 0.4650161862373352 - ], - "min":[ - -1.0722216367721558, - -0.10000000149011612, - -0.10050036013126373 - ], - "type":"VEC3" - }, - { - "bufferView":1, - "componentType":5126, - "count":720, - "type":"VEC3" - }, - { - "bufferView":2, - "componentType":5126, - "count":720, - "type":"VEC2" - }, - { - "bufferView":3, - "componentType":5123, - "count":1260, - "type":"SCALAR" - }, - { - "bufferView":4, - "componentType":5126, - "count":150, - "max":[ - 0.6420668959617615, - 0.27458858489990234, - 0.5718027353286743 - ], - "min":[ - -1.78363037109375, - -0.2425653040409088, - -0.18408852815628052 - ], - "type":"VEC3" - }, - { - "bufferView":5, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":6, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":7, - "componentType":5123, - "count":756, - "type":"SCALAR" - }, - { - "bufferView":8, - "componentType":5126, - "count":150, - "max":[ - 0.6420671343803406, - 0.2745886743068695, - 0.5718027949333191 - ], - "min":[ - -1.7836307287216187, - -0.24256540834903717, - -0.18408851325511932 - ], - "type":"VEC3" - }, - { - "bufferView":9, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":10, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":11, - "componentType":5126, - "count":150, - "max":[ - 0.6420671343803406, - 0.27458858489990234, - 0.5718027949333191 - ], - "min":[ - -1.783630609512329, - -0.2425653636455536, - -0.18408846855163574 - ], - "type":"VEC3" - }, - { - "bufferView":12, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":13, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":14, - "componentType":5126, - "count":150, - "max":[ - 0.6420667767524719, - 0.2745886743068695, - 0.5718027949333191 - ], - "min":[ - -1.783630609512329, - -0.24256554245948792, - -0.18408846855163574 - ], - "type":"VEC3" - }, - { - "bufferView":15, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":16, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":17, - "componentType":5126, - "count":150, - "max":[ - 0.6420665383338928, - 0.2745887041091919, - 0.5718027353286743 - ], - "min":[ - -1.78363037109375, - -0.24256561696529388, - -0.1840885579586029 - ], - "type":"VEC3" - }, - { - "bufferView":18, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":19, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":20, - "componentType":5126, - "count":150, - "max":[ - 0.6420668959617615, - 0.27458861470222473, - 0.5718027949333191 - ], - "min":[ - -1.783630609512329, - -0.24256546795368195, - -0.18408843874931335 - ], - "type":"VEC3" - }, - { - "bufferView":21, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":22, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":23, - "componentType":5126, - "count":150, - "max":[ - 0.642067015171051, - 0.2745887339115143, - 0.5718027353286743 - ], - "min":[ - -1.78363037109375, - -0.24256548285484314, - -0.1840885430574417 - ], - "type":"VEC3" - }, - { - "bufferView":24, - "componentType":5126, - "count":150, - "type":"VEC3" - }, - { - "bufferView":25, - "componentType":5126, - "count":150, - "type":"VEC2" - }, - { - "bufferView":26, - "componentType":5126, - "count":4096, - "max":[ - 32, - 1, - 32 - ], - "min":[ - -32, - -1, - -32 - ], - "type":"VEC3" - }, - { - "bufferView":27, - "componentType":5126, - "count":4096, - "type":"VEC3" - }, - { - "bufferView":28, - "componentType":5126, - "count":4096, - "type":"VEC2" - }, - { - "bufferView":29, - "componentType":5123, - "count":23814, - "type":"SCALAR" - }, - { - "bufferView":30, - "componentType":5126, - "count":4, - "max":[ - 32, - 0.009999999776482582, - 32 - ], - "min":[ - -32, - 0.009999999776482582, - -32 - ], - "type":"VEC3" - }, - { - "bufferView":31, - "componentType":5126, - "count":4, - "type":"VEC3" - }, - { - "bufferView":32, - "componentType":5126, - "count":4, - "type":"VEC2" - }, - { - "bufferView":33, - "componentType":5123, - "count":6, - "type":"SCALAR" - } - ], - "bufferViews":[ - { - "buffer":0, - "byteLength":8640, - "byteOffset":0, - "target":34962 - }, - { - "buffer":0, - "byteLength":8640, - "byteOffset":8640, - "target":34962 - }, - { - "buffer":0, - "byteLength":5760, - "byteOffset":17280, - "target":34962 - }, - { - "buffer":0, - "byteLength":2520, - "byteOffset":23040, - "target":34963 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":25560, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":27360, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":29160, - "target":34962 - }, - { - "buffer":0, - "byteLength":1512, - "byteOffset":30360, - "target":34963 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":31872, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":33672, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":35472, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":36672, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":38472, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":40272, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":41472, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":43272, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":45072, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":46272, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":48072, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":49872, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":51072, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":52872, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":54672, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":55872, - "target":34962 - }, - { - "buffer":0, - "byteLength":1800, - "byteOffset":57672, - "target":34962 - }, - { - "buffer":0, - "byteLength":1200, - "byteOffset":59472, - "target":34962 - }, - { - "buffer":0, - "byteLength":49152, - "byteOffset":60672, - "target":34962 - }, - { - "buffer":0, - "byteLength":49152, - "byteOffset":109824, - "target":34962 - }, - { - "buffer":0, - "byteLength":32768, - "byteOffset":158976, - "target":34962 - }, - { - "buffer":0, - "byteLength":47628, - "byteOffset":191744, - "target":34963 - }, - { - "buffer":0, - "byteLength":48, - "byteOffset":239372, - "target":34962 - }, - { - "buffer":0, - "byteLength":48, - "byteOffset":239420, - "target":34962 - }, - { - "buffer":0, - "byteLength":32, - "byteOffset":239468, - "target":34962 - }, - { - "buffer":0, - "byteLength":12, - "byteOffset":239500, - "target":34963 - } - ], - "samplers":[ - { - "magFilter":9729, - "minFilter":9987 - } - ], - "buffers":[ - { - "byteLength":239512, - "uri":"PalmTree.bin" - } - ] -} diff --git a/assets/models/PalmTree/StylizedWater.png b/assets/models/PalmTree/StylizedWater.png deleted file mode 100644 index a4da3043caca7..0000000000000 Binary files a/assets/models/PalmTree/StylizedWater.png and /dev/null differ diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index 84b3c908fe06d..9c57bf7f3ac55 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -154,10 +154,6 @@ pub struct GpuClusterableObject { pub(crate) spot_light_tan_angle: f32, #[cfg(feature = "spectral_lighting")] pub(crate) monochromaticity: f32, - pub(crate) soft_shadow_size: f32, - pub(crate) shadow_map_near_z: f32, - pub(crate) pad_a: f32, - pub(crate) pad_b: f32, } pub enum GpuClusterableObjects { diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index c37e8f8a3a62f..543b9b8c7ace9 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -262,11 +262,11 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { shader_defs.push("TONEMAP_IN_SHADER".into()); shader_defs.push(ShaderDefVal::UInt( "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(), - 22, + 21, )); shader_defs.push(ShaderDefVal::UInt( "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(), - 23, + 22, )); let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS); diff --git a/crates/bevy_pbr/src/light/directional_light.rs b/crates/bevy_pbr/src/light/directional_light.rs index 10283271e7d74..e5c9fc6fb1661 100644 --- a/crates/bevy_pbr/src/light/directional_light.rs +++ b/crates/bevy_pbr/src/light/directional_light.rs @@ -50,11 +50,7 @@ use super::*; #[derive(Component, Debug, Clone, Reflect)] #[reflect(Component, Default, Debug)] pub struct DirectionalLight { - /// The color of the light. - /// - /// By default, this is white. pub color: Color, - /// Illuminance in lux (lumens per square meter), representing the amount of /// light projected onto surfaces by this light source. Lux is used here /// instead of lumens because a directional light illuminates all surfaces @@ -62,45 +58,10 @@ pub struct DirectionalLight { /// can only be specified for light sources which emit light from a specific /// area. pub illuminance: f32, - - /// Whether this light casts shadows. - /// - /// Note that shadows are rather expensive and become more so with every - /// light that casts them. In general, it's best to aggressively limit the - /// number of lights with shadows enabled to one or two at most. pub shadows_enabled: bool, - - /// Whether soft shadows are enabled, and if so, the size of the light. - /// - /// Soft shadows, also known as *percentage-closer soft shadows* or PCSS, - /// cause shadows to become blurrier (i.e. their penumbra increases in - /// radius) as they extend away from objects. The blurriness of the shadow - /// depends on the size of the light; larger lights result in larger - /// penumbras and therefore blurrier shadows. - /// - /// Currently, soft shadows are rather noisy if not using the temporal mode. - /// If you enable soft shadows, consider choosing - /// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing - /// (TAA) to smooth the noise out over time. - /// - /// Note that soft shadows are significantly more expensive to render than - /// hard shadows. - pub soft_shadow_size: Option, - - /// A value that adjusts the tradeoff between self-shadowing artifacts and - /// proximity of shadows to their casters. - /// - /// This value frequently must be tuned to the specific scene; this is - /// normal and a well-known part of the shadow mapping workflow. If set too - /// low, unsightly shadow patterns appear on objects not in shadow as - /// objects incorrectly cast shadows on themselves, known as *shadow acne*. - /// If set too high, shadows detach from the objects casting them and seem - /// to "fly" off the objects, known as *Peter Panning*. pub shadow_depth_bias: f32, - - /// A bias applied along the direction of the fragment's surface normal. It - /// is scaled to the shadow map's texel size so that it is automatically - /// adjusted to the orthographic projection. + /// A bias applied along the direction of the fragment's surface normal. It is scaled to the + /// shadow map's texel size so that it is automatically adjusted to the orthographic projection. pub shadow_normal_bias: f32, /// The degree to which this light is monochromatic. A value of 0.0 means this light is perfectly polychromatic, /// while a value of 1.0 means this light is perfectly monochromatic. @@ -117,7 +78,6 @@ 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 = "spectral_lighting")] diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 6a318113afb12..165c966dde719 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -580,6 +580,8 @@ pub fn update_point_light_frusta( Or<(Changed, Changed)>, >, ) { + let clip_from_view = + Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z); let view_rotations = CUBE_MAP_FACES .iter() .map(|CubeMapFace { target, up }| Transform::IDENTITY.looking_at(*target, *up)) @@ -596,12 +598,6 @@ pub fn update_point_light_frusta( continue; } - let clip_from_view = Mat4::perspective_infinite_reverse_rh( - std::f32::consts::FRAC_PI_2, - 1.0, - point_light.shadow_map_near_z, - ); - // ignore scale because we don't want to effectively scale light radius and range // by applying those as a view transform to shadow map rendering of objects // and ignore rotation because we want the shadow map projections to align with the axes @@ -644,8 +640,7 @@ pub fn update_spot_light_frusta( let view_backward = transform.back(); let spot_world_from_view = spot_light_world_from_view(transform); - let spot_clip_from_view = - spot_light_clip_from_view(spot_light.outer_angle, spot_light.shadow_map_near_z); + let spot_clip_from_view = spot_light_clip_from_view(spot_light.outer_angle); let clip_from_world = spot_clip_from_view * spot_world_from_view.inverse(); *frustum = Frustum::from_clip_from_world_custom_far( diff --git a/crates/bevy_pbr/src/light/point_light.rs b/crates/bevy_pbr/src/light/point_light.rs index 7fcffba1bf069..a610668d98182 100644 --- a/crates/bevy_pbr/src/light/point_light.rs +++ b/crates/bevy_pbr/src/light/point_light.rs @@ -22,51 +22,25 @@ use super::*; pub struct PointLight { /// The color of this light source. pub color: Color, - /// Luminous power in lumens, representing the amount of light emitted by this source in all directions. pub intensity: f32, - /// Cut-off for the light's area-of-effect. Fragments outside this range will not be affected by /// this light at all, so it's important to tune this together with `intensity` to prevent hard /// lighting cut-offs. pub range: f32, - - /// Simulates a light source coming from a spherical volume with the given - /// radius. - /// - /// This affects the size of specular highlights created by this light, as - /// well as the soft shadow penumbra size. Because of this, large values may - /// not produce the intended result -- for example, light radius does not - /// affect shadow softness or diffuse lighting. + /// Simulates a light source coming from a spherical volume with the given radius. Only affects + /// the size of specular highlights created by this light. Because of this, large values may not + /// produce the intended result -- for example, light radius does not affect shadow softness or + /// diffuse lighting. pub radius: f32, - /// Whether this light casts shadows. pub shadows_enabled: bool, - - /// Whether soft shadows are enabled. - /// - /// Soft shadows, also known as *percentage-closer soft shadows* or PCSS, - /// cause shadows to become blurrier (i.e. their penumbra increases in - /// radius) as they extend away from objects. The blurriness of the shadow - /// depends on the [`PointLight::radius`] of the light; larger lights result - /// in larger penumbras and therefore blurrier shadows. - /// - /// Currently, soft shadows are rather noisy if not using the temporal mode. - /// If you enable soft shadows, consider choosing - /// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing - /// (TAA) to smooth the noise out over time. - /// - /// Note that soft shadows are significantly more expensive to render than - /// hard shadows. - pub soft_shadows_enabled: bool, - /// A bias used when sampling shadow maps to avoid "shadow-acne", or false shadow occlusions /// that happen as a result of shadow-map fragments not mapping 1:1 to screen-space fragments. /// Too high of a depth bias can lead to shadows detaching from their casters, or /// "peter-panning". This bias can be tuned together with `shadow_normal_bias` to correct shadow /// artifacts for a given scene. pub shadow_depth_bias: f32, - /// A bias applied along the direction of the fragment's surface normal. It is scaled to the /// shadow map's texel size so that it can be small close to the camera and gets larger further /// away. @@ -78,14 +52,6 @@ pub struct PointLight { /// Combining non-zero values with non-spectral colors is not physically correct, but can be used for artistic effect. #[cfg(feature = "spectral_lighting")] pub monochromaticity: f32, - - /// The distance from the light to near Z plane in the shadow map. - /// - /// Objects closer than this distance to the light won't cast shadows. - /// Setting this higher increases the shadow map's precision. - /// - /// This only has an effect if shadows are enabled. - pub shadow_map_near_z: f32, } impl Default for PointLight { @@ -99,12 +65,10 @@ 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, #[cfg(feature = "spectral_lighting")] monochromaticity: 0.0, - shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z, } } } @@ -112,5 +76,4 @@ impl Default for PointLight { impl PointLight { pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.08; pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6; - pub const DEFAULT_SHADOW_MAP_NEAR_Z: f32 = 0.1; } diff --git a/crates/bevy_pbr/src/light/spot_light.rs b/crates/bevy_pbr/src/light/spot_light.rs index 7d3d4c036b5c8..032a996d51382 100644 --- a/crates/bevy_pbr/src/light/spot_light.rs +++ b/crates/bevy_pbr/src/light/spot_light.rs @@ -7,85 +7,23 @@ use super::*; #[derive(Component, Debug, Clone, Copy, Reflect)] #[reflect(Component, Default, Debug)] pub struct SpotLight { - /// The color of the light. - /// - /// By default, this is white. pub color: Color, - /// Luminous power in lumens, representing the amount of light emitted by this source in all directions. pub intensity: f32, - - /// Range in meters that this light illuminates. - /// - /// Note that this value affects resolution of the shadow maps; generally, the - /// higher you set it, the lower-resolution your shadow maps will be. - /// Consequently, you should set this value to be only the size that you need. pub range: f32, - - /// Simulates a light source coming from a spherical volume with the given - /// radius. - /// - /// This affects the size of specular highlights created by this light, as - /// well as the soft shadow penumbra size. Because of this, large values may - /// not produce the intended result -- for example, light radius does not - /// affect shadow softness or diffuse lighting. pub radius: f32, - - /// Whether this light casts shadows. - /// - /// Note that shadows are rather expensive and become more so with every - /// light that casts them. In general, it's best to aggressively limit the - /// number of lights with shadows enabled to one or two at most. pub shadows_enabled: bool, - - /// Whether soft shadows are enabled. - /// - /// Soft shadows, also known as *percentage-closer soft shadows* or PCSS, - /// cause shadows to become blurrier (i.e. their penumbra increases in - /// radius) as they extend away from objects. The blurriness of the shadow - /// depends on the [`SpotLight::radius`] of the light; larger lights result in larger - /// penumbras and therefore blurrier shadows. - /// - /// Currently, soft shadows are rather noisy if not using the temporal mode. - /// If you enable soft shadows, consider choosing - /// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing - /// (TAA) to smooth the noise out over time. - /// - /// Note that soft shadows are significantly more expensive to render than - /// hard shadows. - pub soft_shadows_enabled: bool, - - /// A value that adjusts the tradeoff between self-shadowing artifacts and - /// proximity of shadows to their casters. - /// - /// This value frequently must be tuned to the specific scene; this is - /// normal and a well-known part of the shadow mapping workflow. If set too - /// low, unsightly shadow patterns appear on objects not in shadow as - /// objects incorrectly cast shadows on themselves, known as *shadow acne*. - /// If set too high, shadows detach from the objects casting them and seem - /// to "fly" off the objects, known as *Peter Panning*. pub shadow_depth_bias: f32, - /// A bias applied along the direction of the fragment's surface normal. It is scaled to the /// shadow map's texel size so that it can be small close to the camera and gets larger further /// away. pub shadow_normal_bias: f32, - - /// The distance from the light to the near Z plane in the shadow map. - /// - /// Objects closer than this distance to the light won't cast shadows. - /// Setting this higher increases the shadow map's precision. - /// - /// This only has an effect if shadows are enabled. - pub shadow_map_near_z: f32, - /// Angle defining the distance from the spot light direction to the outer limit /// of the light's cone of effect. /// `outer_angle` should be < `PI / 2.0`. /// `PI / 2.0` defines a hemispherical spot light, but shadows become very blocky as the angle /// approaches this limit. pub outer_angle: f32, - /// Angle defining the distance from the spot light direction to the inner limit /// of the light's cone of effect. /// Light is attenuated from `inner_angle` to `outer_angle` to give a smooth falloff. @@ -103,7 +41,6 @@ pub struct SpotLight { impl SpotLight { pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02; pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 1.8; - pub const DEFAULT_SHADOW_MAP_NEAR_Z: f32 = 0.1; } impl Default for SpotLight { @@ -118,10 +55,8 @@ 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: std::f32::consts::FRAC_PI_4, #[cfg(feature = "spectral_lighting")] diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 88f3ddf918b76..12f636ea5ea19 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -20,7 +20,6 @@ use bevy_render::{ Extract, }; use bevy_transform::{components::GlobalTransform, prelude::Transform}; -use bevy_utils::prelude::default; #[cfg(feature = "trace")] use bevy_utils::tracing::info_span; use bevy_utils::tracing::{error, warn}; @@ -38,10 +37,8 @@ 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 render_layers: RenderLayers, #[cfg(feature = "spectral_lighting")] @@ -55,7 +52,6 @@ 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, @@ -94,7 +90,6 @@ pub struct GpuDirectionalLight { color: Vec4, dir_to_light: Vec3, flags: u32, - soft_shadow_size: f32, shadow_depth_bias: f32, shadow_normal_bias: f32, num_cascades: u32, @@ -158,10 +153,8 @@ pub const MAX_CASCADES_PER_LIGHT: usize = 1; #[derive(Resource, Clone)] pub struct ShadowSamplers { - pub point_light_comparison_sampler: Sampler, - pub point_light_linear_sampler: Sampler, - pub directional_light_comparison_sampler: Sampler, - pub directional_light_linear_sampler: Sampler, + pub point_light_sampler: Sampler, + pub directional_light_sampler: Sampler, } // TODO: this pattern for initializing the shaders / pipeline isn't ideal. this should be handled by the asset system @@ -169,30 +162,27 @@ impl FromWorld for ShadowSamplers { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let base_sampler_descriptor = SamplerDescriptor { - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - address_mode_w: AddressMode::ClampToEdge, - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Nearest, - ..default() - }; - ShadowSamplers { - point_light_comparison_sampler: render_device.create_sampler(&SamplerDescriptor { + point_light_sampler: render_device.create_sampler(&SamplerDescriptor { + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + address_mode_w: AddressMode::ClampToEdge, + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + mipmap_filter: FilterMode::Nearest, compare: Some(CompareFunction::GreaterEqual), - ..base_sampler_descriptor + ..Default::default() + }), + directional_light_sampler: render_device.create_sampler(&SamplerDescriptor { + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + address_mode_w: AddressMode::ClampToEdge, + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + mipmap_filter: FilterMode::Nearest, + compare: Some(CompareFunction::GreaterEqual), + ..Default::default() }), - point_light_linear_sampler: render_device.create_sampler(&base_sampler_descriptor), - directional_light_comparison_sampler: render_device.create_sampler( - &SamplerDescriptor { - compare: Some(CompareFunction::GreaterEqual), - ..base_sampler_descriptor - }, - ), - directional_light_linear_sampler: render_device - .create_sampler(&base_sampler_descriptor), } } } @@ -289,13 +279,11 @@ 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 * point_light_texel_size * std::f32::consts::SQRT_2, - shadow_map_near_z: point_light.shadow_map_near_z, spot_light_angles: None, render_layers: render_layers.unwrap_or_default().clone(), #[cfg(feature = "spectral_lighting")] @@ -349,13 +337,11 @@ 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 * texel_size * std::f32::consts::SQRT_2, - shadow_map_near_z: spot_light.shadow_map_near_z, spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), render_layers: render_layers.unwrap_or_default().clone(), #[cfg(feature = "spectral_lighting")] @@ -395,7 +381,6 @@ pub fn extract_lights( illuminance: directional_light.illuminance, transform: *transform, volumetric: volumetric_light.is_some(), - soft_shadow_size: directional_light.soft_shadow_size, 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 @@ -412,6 +397,8 @@ pub fn extract_lights( } } +pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; + pub(crate) struct CubeMapFace { pub(crate) target: Vec3, pub(crate) up: Vec3, @@ -556,9 +543,9 @@ pub(crate) fn spot_light_world_from_view(transform: &GlobalTransform) -> Mat4 { ) } -pub(crate) fn spot_light_clip_from_view(angle: f32, near_z: f32) -> Mat4 { +pub(crate) fn spot_light_clip_from_view(angle: f32) -> Mat4 { // spot light projection FOV is 2x the angle from spot light center to outer edge - Mat4::perspective_infinite_reverse_rh(angle * 2.0, 1.0, near_z) + Mat4::perspective_infinite_reverse_rh(angle * 2.0, 1.0, POINT_LIGHT_NEAR_Z) } #[allow(clippy::too_many_arguments)] @@ -606,6 +593,8 @@ pub fn prepare_lights( }; // Pre-calculate for PointLights + let cube_face_projection = + Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z); let cube_face_rotations = CUBE_MAP_FACES .iter() .map(|CubeMapFace { target, up }| Transform::IDENTITY.looking_at(*target, *up)) @@ -740,12 +729,6 @@ pub fn prepare_lights( flags |= PointLightFlags::SHADOWS_ENABLED; } - let cube_face_projection = Mat4::perspective_infinite_reverse_rh( - std::f32::consts::FRAC_PI_2, - 1.0, - light.shadow_map_near_z, - ); - let (light_custom_data, spot_light_tan_angle) = match light.spot_light_angles { Some((inner, outer)) => { let light_direction = light.transform.forward(); @@ -790,19 +773,11 @@ pub fn prepare_lights( flags: flags.bits() | (light.render_layers.bits_u16() as u32) << PointLightFlags::RENDER_LAYERS_SHIFT_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, #[cfg(feature = "spectral_lighting")] monochromaticity: light.monochromaticity, - pad_a: 0.0, - pad_b: 0.0, }); global_light_meta.entity_to_index.insert(entity, index); } @@ -846,7 +821,6 @@ pub fn prepare_lights( flags: flags.bits() | (light.render_layers.bits_u16() as u32) << DirectionalLightFlags::RENDER_LAYERS_SHIFT_BITS, - soft_shadow_size: light.soft_shadow_size.unwrap_or_default(), shadow_depth_bias: light.shadow_depth_bias, shadow_normal_bias: light.shadow_normal_bias, num_cascades: num_cascades as u32, @@ -1017,12 +991,6 @@ pub fn prepare_lights( // and ignore rotation because we want the shadow map projections to align with the axes let view_translation = GlobalTransform::from_translation(light.transform.translation()); - let cube_face_projection = Mat4::perspective_infinite_reverse_rh( - std::f32::consts::FRAC_PI_2, - 1.0, - light.shadow_map_near_z, - ); - for (face_index, (view_rotation, frustum)) in cube_face_rotations .iter() .zip(&point_light_frusta.unwrap().frusta) @@ -1106,7 +1074,7 @@ pub fn prepare_lights( let angle = light.spot_light_angles.expect("lights should be sorted so that \ [point_light_count..point_light_count + spot_light_shadow_maps_count] are spot lights").1; - let spot_projection = spot_light_clip_from_view(angle, light.shadow_map_near_z); + let spot_projection = spot_light_clip_from_view(angle); let mut first = false; let base_array_layer = (num_directional_cascades_enabled + light_index) as u32; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 096bb853aea76..366b21880fff6 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1859,11 +1859,11 @@ impl SpecializedMeshPipeline for MeshPipeline { shader_defs.push("TONEMAP_IN_SHADER".into()); shader_defs.push(ShaderDefVal::UInt( "TONEMAPPING_LUT_TEXTURE_BINDING_INDEX".into(), - 23, + 21, )); shader_defs.push(ShaderDefVal::UInt( "TONEMAPPING_LUT_SAMPLER_BINDING_INDEX".into(), - 24, + 22, )); let method = key.intersection(MeshPipelineKey::TONEMAP_METHOD_RESERVED_BITS); diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 9446b3c9a9180..d0a506e9c3e42 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -213,13 +213,11 @@ fn layout_entries( ))] texture_cube(TextureSampleType::Depth), ), - // Point Shadow Texture Array Comparison Sampler + // Point Shadow Texture Array Sampler (3, sampler(SamplerBindingType::Comparison)), - // Point Shadow Texture Array Linear Sampler - (4, sampler(SamplerBindingType::Filtering)), // Directional Shadow Texture Array ( - 5, + 4, #[cfg(any( not(feature = "webgl"), not(target_arch = "wasm32"), @@ -229,13 +227,11 @@ fn layout_entries( #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] texture_2d(TextureSampleType::Depth), ), - // Directional Shadow Texture Array Comparison Sampler - (6, sampler(SamplerBindingType::Comparison)), - // Directional Shadow Texture Array Linear Sampler - (7, sampler(SamplerBindingType::Filtering)), - // PointLights + // Directional Shadow Texture Array Sampler + (5, sampler(SamplerBindingType::Comparison)), + // ClusterableObjects ( - 8, + 6, buffer_layout( clustered_forward_buffer_binding_type, false, @@ -246,7 +242,7 @@ fn layout_entries( ), // ClusteredLightIndexLists ( - 9, + 7, buffer_layout( clustered_forward_buffer_binding_type, false, @@ -259,7 +255,7 @@ fn layout_entries( ), // ClusterOffsetsAndCounts ( - 10, + 8, buffer_layout( clustered_forward_buffer_binding_type, false, @@ -270,16 +266,16 @@ fn layout_entries( ), // Globals ( - 11, + 9, uniform_buffer::(false).visibility(ShaderStages::VERTEX_FRAGMENT), ), // Fog - (12, uniform_buffer::(true)), + (10, uniform_buffer::(true)), // Light probes - (13, uniform_buffer::(true)), + (11, uniform_buffer::(true)), // Visibility ranges ( - 14, + 12, buffer_layout( visibility_ranges_buffer_binding_type, false, @@ -288,10 +284,10 @@ fn layout_entries( .visibility(ShaderStages::VERTEX), ), // Screen space reflection settings - (15, uniform_buffer::(true)), + (13, uniform_buffer::(true)), // Screen space ambient occlusion texture ( - 16, + 14, texture_2d(TextureSampleType::Float { filterable: false }), ), ), @@ -300,10 +296,10 @@ fn layout_entries( // EnvironmentMapLight let environment_map_entries = environment_map::get_bind_group_layout_entries(render_device); entries = entries.extend_with_indices(( - (17, environment_map_entries[0]), - (18, environment_map_entries[1]), - (19, environment_map_entries[2]), - (20, environment_map_entries[3]), + (15, environment_map_entries[0]), + (16, environment_map_entries[1]), + (17, environment_map_entries[2]), + (18, environment_map_entries[3]), )); // Irradiance volumes @@ -311,16 +307,16 @@ fn layout_entries( let irradiance_volume_entries = irradiance_volume::get_bind_group_layout_entries(render_device); entries = entries.extend_with_indices(( - (21, irradiance_volume_entries[0]), - (22, irradiance_volume_entries[1]), + (19, irradiance_volume_entries[0]), + (20, irradiance_volume_entries[1]), )); } // Tonemapping let tonemapping_lut_entries = get_lut_bind_group_layout_entries(); entries = entries.extend_with_indices(( - (23, tonemapping_lut_entries[0]), - (24, tonemapping_lut_entries[1]), + (21, tonemapping_lut_entries[0]), + (22, tonemapping_lut_entries[1]), )); // Prepass @@ -330,7 +326,7 @@ fn layout_entries( { for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key) .iter() - .zip([25, 26, 27, 28]) + .zip([23, 24, 25, 26]) { if let Some(entry) = entry { entries = entries.extend_with_indices(((binding as u32, *entry),)); @@ -341,10 +337,10 @@ fn layout_entries( // View Transmission Texture entries = entries.extend_with_indices(( ( - 29, + 27, texture_2d(TextureSampleType::Float { filterable: true }), ), - (30, sampler(SamplerBindingType::Filtering)), + (28, sampler(SamplerBindingType::Filtering)), )); entries.to_vec() @@ -531,25 +527,23 @@ pub fn prepare_mesh_view_bind_groups( (0, view_binding.clone()), (1, light_binding.clone()), (2, &shadow_bindings.point_light_depth_texture_view), - (3, &shadow_samplers.point_light_comparison_sampler), - (4, &shadow_samplers.point_light_linear_sampler), - (5, &shadow_bindings.directional_light_depth_texture_view), - (6, &shadow_samplers.directional_light_comparison_sampler), - (7, &shadow_samplers.directional_light_linear_sampler), - (8, clusterable_objects_binding.clone()), + (3, &shadow_samplers.point_light_sampler), + (4, &shadow_bindings.directional_light_depth_texture_view), + (5, &shadow_samplers.directional_light_sampler), + (6, clusterable_objects_binding.clone()), ( - 9, + 7, cluster_bindings .clusterable_object_index_lists_binding() .unwrap(), ), - (10, cluster_bindings.offsets_and_counts_binding().unwrap()), - (11, globals.clone()), - (12, fog_binding.clone()), - (13, light_probes_binding.clone()), - (14, visibility_ranges_buffer.as_entire_binding()), - (15, ssr_binding.clone()), - (16, ssao_view), + (8, cluster_bindings.offsets_and_counts_binding().unwrap()), + (9, globals.clone()), + (10, fog_binding.clone()), + (11, light_probes_binding.clone()), + (12, visibility_ranges_buffer.as_entire_binding()), + (13, ssr_binding.clone()), + (14, ssao_view), )); let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get( @@ -566,10 +560,10 @@ pub fn prepare_mesh_view_bind_groups( sampler, } => { entries = entries.extend_with_indices(( - (17, diffuse_texture_view), - (18, specular_texture_view), - (19, sampler), - (20, environment_map_binding.clone()), + (15, diffuse_texture_view), + (16, specular_texture_view), + (17, sampler), + (18, environment_map_binding.clone()), )); } RenderViewEnvironmentMapBindGroupEntries::Multiple { @@ -578,10 +572,10 @@ pub fn prepare_mesh_view_bind_groups( sampler, } => { entries = entries.extend_with_indices(( - (17, diffuse_texture_views.as_slice()), - (18, specular_texture_views.as_slice()), - (19, sampler), - (20, environment_map_binding.clone()), + (15, diffuse_texture_views.as_slice()), + (16, specular_texture_views.as_slice()), + (17, sampler), + (18, environment_map_binding.clone()), )); } } @@ -602,21 +596,21 @@ pub fn prepare_mesh_view_bind_groups( texture_view, sampler, }) => { - entries = entries.extend_with_indices(((21, texture_view), (22, sampler))); + entries = entries.extend_with_indices(((19, texture_view), (20, sampler))); } Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple { ref texture_views, sampler, }) => { entries = entries - .extend_with_indices(((21, texture_views.as_slice()), (22, sampler))); + .extend_with_indices(((19, texture_views.as_slice()), (20, sampler))); } None => {} } let lut_bindings = get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image); - entries = entries.extend_with_indices(((23, lut_bindings.0), (24, lut_bindings.1))); + entries = entries.extend_with_indices(((21, lut_bindings.0), (22, lut_bindings.1))); // When using WebGL, we can't have a depth texture with multisampling let prepass_bindings; @@ -626,7 +620,7 @@ pub fn prepare_mesh_view_bind_groups( for (binding, index) in prepass_bindings .iter() .map(Option::as_ref) - .zip([25, 26, 27, 28]) + .zip([23, 24, 25, 26]) .flat_map(|(b, i)| b.map(|b| (b, i))) { entries = entries.extend_with_indices(((index, binding),)); @@ -642,7 +636,7 @@ pub fn prepare_mesh_view_bind_groups( .unwrap_or(&fallback_image_zero.sampler); entries = - entries.extend_with_indices(((29, transmission_view), (30, transmission_sampler))); + entries.extend_with_indices(((27, transmission_view), (28, transmission_sampler))); commands.entity(entity).insert(MeshViewBindGroup { value: render_device.create_bind_group("mesh_view_bind_group", layout, &entries), diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl index dfda3a576b317..5036e81673e98 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl @@ -13,91 +13,88 @@ #else @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; -@group(0) @binding(4) var point_shadow_textures_linear_sampler: sampler; +@group(0) @binding(3) var point_shadow_textures_sampler: sampler_comparison; #ifdef NO_ARRAY_TEXTURES_SUPPORT -@group(0) @binding(5) var directional_shadow_textures: texture_depth_2d; +@group(0) @binding(4) var directional_shadow_textures: texture_depth_2d; #else -@group(0) @binding(5) var directional_shadow_textures: texture_depth_2d_array; +@group(0) @binding(4) var directional_shadow_textures: texture_depth_2d_array; #endif -@group(0) @binding(6) var directional_shadow_textures_comparison_sampler: sampler_comparison; -@group(0) @binding(7) var directional_shadow_textures_linear_sampler: sampler; +@group(0) @binding(5) var directional_shadow_textures_sampler: sampler_comparison; #if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3 -@group(0) @binding(8) var clusterable_objects: types::ClusterableObjects; -@group(0) @binding(9) var clusterable_object_index_lists: types::ClusterLightIndexLists; -@group(0) @binding(10) var cluster_offsets_and_counts: types::ClusterOffsetsAndCounts; +@group(0) @binding(6) var clusterable_objects: types::ClusterableObjects; +@group(0) @binding(7) var clusterable_object_index_lists: types::ClusterLightIndexLists; +@group(0) @binding(8) var cluster_offsets_and_counts: types::ClusterOffsetsAndCounts; #else -@group(0) @binding(8) var clusterable_objects: types::ClusterableObjects; -@group(0) @binding(9) var clusterable_object_index_lists: types::ClusterLightIndexLists; -@group(0) @binding(10) var cluster_offsets_and_counts: types::ClusterOffsetsAndCounts; +@group(0) @binding(6) var clusterable_objects: types::ClusterableObjects; +@group(0) @binding(7) var clusterable_object_index_lists: types::ClusterLightIndexLists; +@group(0) @binding(8) var cluster_offsets_and_counts: types::ClusterOffsetsAndCounts; #endif -@group(0) @binding(11) var globals: Globals; -@group(0) @binding(12) var fog: types::Fog; -@group(0) @binding(13) var light_probes: types::LightProbes; +@group(0) @binding(9) var globals: Globals; +@group(0) @binding(10) var fog: types::Fog; +@group(0) @binding(11) var light_probes: types::LightProbes; const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u; #if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6 -@group(0) @binding(14) var visibility_ranges: array>; +@group(0) @binding(12) var visibility_ranges: array>; #else -@group(0) @binding(14) var visibility_ranges: array, VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE>; +@group(0) @binding(12) var visibility_ranges: array, VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE>; #endif -@group(0) @binding(15) var ssr_settings: types::ScreenSpaceReflectionsSettings; -@group(0) @binding(16) var screen_space_ambient_occlusion_texture: texture_2d; +@group(0) @binding(13) var ssr_settings: types::ScreenSpaceReflectionsSettings; +@group(0) @binding(14) var screen_space_ambient_occlusion_texture: texture_2d; #ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY -@group(0) @binding(17) var diffuse_environment_maps: binding_array, 8u>; -@group(0) @binding(18) var specular_environment_maps: binding_array, 8u>; +@group(0) @binding(15) var diffuse_environment_maps: binding_array, 8u>; +@group(0) @binding(16) var specular_environment_maps: binding_array, 8u>; #else -@group(0) @binding(17) var diffuse_environment_map: texture_cube; -@group(0) @binding(18) var specular_environment_map: texture_cube; +@group(0) @binding(15) var diffuse_environment_map: texture_cube; +@group(0) @binding(16) var specular_environment_map: texture_cube; #endif -@group(0) @binding(19) var environment_map_sampler: sampler; -@group(0) @binding(20) var environment_map_uniform: types::EnvironmentMapUniform; +@group(0) @binding(17) var environment_map_sampler: sampler; +@group(0) @binding(18) var environment_map_uniform: types::EnvironmentMapUniform; #ifdef IRRADIANCE_VOLUMES_ARE_USABLE #ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY -@group(0) @binding(21) var irradiance_volumes: binding_array, 8u>; +@group(0) @binding(19) var irradiance_volumes: binding_array, 8u>; #else -@group(0) @binding(21) var irradiance_volume: texture_3d; +@group(0) @binding(19) var irradiance_volume: texture_3d; #endif -@group(0) @binding(22) var irradiance_volume_sampler: sampler; +@group(0) @binding(20) var irradiance_volume_sampler: sampler; #endif -// NB: If you change these, make sure to update `tonemapping_shared.wgsl` too. -@group(0) @binding(23) var dt_lut_texture: texture_3d; -@group(0) @binding(24) var dt_lut_sampler: sampler; +@group(0) @binding(21) var dt_lut_texture: texture_3d; +@group(0) @binding(22) var dt_lut_sampler: sampler; #ifdef MULTISAMPLED #ifdef DEPTH_PREPASS -@group(0) @binding(25) var depth_prepass_texture: texture_depth_multisampled_2d; +@group(0) @binding(23) var depth_prepass_texture: texture_depth_multisampled_2d; #endif // DEPTH_PREPASS #ifdef NORMAL_PREPASS -@group(0) @binding(26) var normal_prepass_texture: texture_multisampled_2d; +@group(0) @binding(24) var normal_prepass_texture: texture_multisampled_2d; #endif // NORMAL_PREPASS #ifdef MOTION_VECTOR_PREPASS -@group(0) @binding(27) var motion_vector_prepass_texture: texture_multisampled_2d; +@group(0) @binding(25) var motion_vector_prepass_texture: texture_multisampled_2d; #endif // MOTION_VECTOR_PREPASS #else // MULTISAMPLED #ifdef DEPTH_PREPASS -@group(0) @binding(25) var depth_prepass_texture: texture_depth_2d; +@group(0) @binding(23) var depth_prepass_texture: texture_depth_2d; #endif // DEPTH_PREPASS #ifdef NORMAL_PREPASS -@group(0) @binding(26) var normal_prepass_texture: texture_2d; +@group(0) @binding(24) var normal_prepass_texture: texture_2d; #endif // NORMAL_PREPASS #ifdef MOTION_VECTOR_PREPASS -@group(0) @binding(27) var motion_vector_prepass_texture: texture_2d; +@group(0) @binding(25) var motion_vector_prepass_texture: texture_2d; #endif // MOTION_VECTOR_PREPASS #endif // MULTISAMPLED #ifdef DEFERRED_PREPASS -@group(0) @binding(28) var deferred_prepass_texture: texture_2d; +@group(0) @binding(26) var deferred_prepass_texture: texture_2d; #endif // DEFERRED_PREPASS -@group(0) @binding(29) var view_transmission_texture: texture_2d; -@group(0) @binding(30) var view_transmission_sampler: sampler; +@group(0) @binding(27) var view_transmission_texture: texture_2d; +@group(0) @binding(28) var view_transmission_sampler: sampler; diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index cdeb406e91065..48faf34b88b1e 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -14,10 +14,6 @@ struct ClusterableObject { #ifdef SPECTRAL_LIGHTING monochromaticity: f32, #endif - soft_shadow_size: f32, - shadow_map_near_z: f32, - pad_a: f32, - pad_b: f32, }; const POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT: u32 = 1u; @@ -36,7 +32,6 @@ struct DirectionalLight { direction_to_light: vec3, // 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options. flags: u32, - soft_shadow_size: f32, shadow_depth_bias: f32, shadow_normal_bias: f32, num_cascades: u32, diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 93a30f005de16..bb9a3e8977d66 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -456,14 +456,8 @@ fn apply_pbr_lighting( var shadow: f32 = 1.0; if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u - && (view_bindings::clusterable_objects.data[light_id].flags & - mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - shadow = shadows::fetch_spot_shadow( - light_id, - in.world_position, - in.world_normal, - view_bindings::clusterable_objects.data[light_id].shadow_map_near_z, - ); + && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + shadow = shadows::fetch_spot_shadow(light_id, in.world_position, in.world_normal); } let light_contrib = lighting::spot_light(light_id, &lighting_input); @@ -482,12 +476,7 @@ fn apply_pbr_lighting( var transmitted_shadow: f32 = 1.0; if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { - transmitted_shadow = shadows::fetch_spot_shadow( - light_id, - diffuse_transmissive_lobe_world_position, - -in.world_normal, - view_bindings::clusterable_objects.data[light_id].shadow_map_near_z, - ); + transmitted_shadow = shadows::fetch_spot_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); } let transmitted_light_contrib = diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_pbr/src/render/shadow_sampling.wgsl index 0c546a37c6d3e..ec155cf3fcb77 100644 --- a/crates/bevy_pbr/src/render/shadow_sampling.wgsl +++ b/crates/bevy_pbr/src/render/shadow_sampling.wgsl @@ -12,14 +12,14 @@ fn sample_shadow_map_hardware(light_local: vec2, depth: f32, array_index: i #ifdef NO_ARRAY_TEXTURES_SUPPORT return textureSampleCompare( view_bindings::directional_shadow_textures, - view_bindings::directional_shadow_textures_comparison_sampler, + view_bindings::directional_shadow_textures_sampler, light_local, depth, ); #else return textureSampleCompareLevel( view_bindings::directional_shadow_textures, - view_bindings::directional_shadow_textures_comparison_sampler, + view_bindings::directional_shadow_textures_sampler, light_local, array_index, depth, @@ -27,40 +27,6 @@ fn sample_shadow_map_hardware(light_local: vec2, depth: f32, array_index: i #endif } -// Does a single sample of the blocker search, a part of the PCSS algorithm. -// This is the variant used for directional lights. -fn search_for_blockers_in_shadow_map_hardware( - light_local: vec2, - depth: f32, - array_index: i32, -) -> vec2 { -#ifdef WEBGL2 - // Make sure that the WebGL 2 compiler doesn't see `sampled_depth` sampled - // with different samplers, or it'll blow up. - return vec2(0.0); -#else // WEBGL2 - -#ifdef NO_ARRAY_TEXTURES_SUPPORT - let sampled_depth = textureSampleLevel( - view_bindings::directional_shadow_textures, - view_bindings::directional_shadow_textures_linear_sampler, - light_local, - 0.0, - ); -#else // NO_ARRAY_TEXTURES_SUPPORT - let sampled_depth = textureSampleLevel( - view_bindings::directional_shadow_textures, - view_bindings::directional_shadow_textures_linear_sampler, - light_local, - array_index, - 0.0, - ); -#endif // NO_ARRAY_TEXTURES_SUPPORT - return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); - -#endif // WEBGL2 -} - // Numbers determined by trial and error that gave nice results. const SPOT_SHADOW_TEXEL_SIZE: f32 = 0.0134277345; const POINT_SHADOW_SCALE: f32 = 0.003; @@ -147,9 +113,9 @@ fn map(min1: f32, max1: f32, min2: f32, max2: f32, value: f32) -> f32 { // Creates a random rotation matrix using interleaved gradient noise. // // See: https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare/ -fn random_rotation_matrix(scale: vec2, temporal: bool) -> mat2x2 { +fn random_rotation_matrix(scale: vec2) -> mat2x2 { let random_angle = 2.0 * PI * interleaved_gradient_noise( - scale, select(1u, view_bindings::globals.frame_count, temporal)); + scale, view_bindings::globals.frame_count); let m = vec2(sin(random_angle), cos(random_angle)); return mat2x2( m.y, -m.x, @@ -157,28 +123,13 @@ fn random_rotation_matrix(scale: vec2, temporal: bool) -> mat2x2 { ); } -// Calculates the distance between spiral samples for the given texel size and -// penumbra size. This is used for the Jimenez '14 (i.e. temporal) variant of -// shadow sampling. -fn calculate_uv_offset_scale_jimenez_fourteen(texel_size: f32, blur_size: f32) -> vec2 { +fn sample_shadow_map_jimenez_fourteen(light_local: vec2, depth: f32, array_index: i32, texel_size: f32) -> f32 { let shadow_map_size = vec2(textureDimensions(view_bindings::directional_shadow_textures)); + let rotation_matrix = random_rotation_matrix(light_local * shadow_map_size); // Empirically chosen fudge factor to make PCF look better across different CSM cascades let f = map(0.00390625, 0.022949219, 0.015, 0.035, texel_size); - return f * blur_size / (texel_size * shadow_map_size); -} - -fn sample_shadow_map_jimenez_fourteen( - light_local: vec2, - depth: f32, - array_index: i32, - texel_size: f32, - blur_size: f32, - temporal: bool, -) -> f32 { - let shadow_map_size = vec2(textureDimensions(view_bindings::directional_shadow_textures)); - let rotation_matrix = random_rotation_matrix(light_local * shadow_map_size, temporal); - let uv_offset_scale = calculate_uv_offset_scale_jimenez_fourteen(texel_size, blur_size); + let uv_offset_scale = f / (texel_size * shadow_map_size); // https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare (slides 120-135) let sample_offset0 = (rotation_matrix * utils::SPIRAL_OFFSET_0_) * uv_offset_scale; @@ -202,57 +153,11 @@ fn sample_shadow_map_jimenez_fourteen( return sum / 8.0; } -// Performs the blocker search portion of percentage-closer soft shadows (PCSS). -// This is the variation used for directional lights. -// -// We can't use Castano '13 here because that has a hard-wired fixed size, while -// the PCSS algorithm requires a search size that varies based on the size of -// the light. So we instead use the D3D sample point positions, spaced according -// to the search size, to provide a sample pattern in a similar manner to the -// cubemap sampling approach we use for PCF. -// -// `search_size` is the size of the search region in texels. -fn search_for_blockers_in_shadow_map( - light_local: vec2, - depth: f32, - array_index: i32, - texel_size: f32, - search_size: f32, -) -> f32 { - let shadow_map_size = vec2(textureDimensions(view_bindings::directional_shadow_textures)); - let uv_offset_scale = search_size / (texel_size * shadow_map_size); - - let offset0 = D3D_SAMPLE_POINT_POSITIONS[0] * uv_offset_scale; - let offset1 = D3D_SAMPLE_POINT_POSITIONS[1] * uv_offset_scale; - let offset2 = D3D_SAMPLE_POINT_POSITIONS[2] * uv_offset_scale; - let offset3 = D3D_SAMPLE_POINT_POSITIONS[3] * uv_offset_scale; - let offset4 = D3D_SAMPLE_POINT_POSITIONS[4] * uv_offset_scale; - let offset5 = D3D_SAMPLE_POINT_POSITIONS[5] * uv_offset_scale; - let offset6 = D3D_SAMPLE_POINT_POSITIONS[6] * uv_offset_scale; - let offset7 = D3D_SAMPLE_POINT_POSITIONS[7] * uv_offset_scale; - - var sum = vec2(0.0); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset0, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset1, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset2, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset3, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset4, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset5, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset6, depth, array_index); - sum += search_for_blockers_in_shadow_map_hardware(light_local + offset7, depth, array_index); - - if (sum.y == 0.0) { - return 0.0; - } - return sum.x / sum.y; -} - fn sample_shadow_map(light_local: vec2, depth: f32, array_index: i32, texel_size: f32) -> f32 { #ifdef SHADOW_FILTER_METHOD_GAUSSIAN return sample_shadow_map_castano_thirteen(light_local, depth, array_index); #else ifdef SHADOW_FILTER_METHOD_TEMPORAL - return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, 1.0, true); + return sample_shadow_map_jimenez_fourteen(light_local, depth, array_index, texel_size); #else ifdef SHADOW_FILTER_METHOD_HARDWARE_2X2 return sample_shadow_map_hardware(light_local, depth, array_index); #else @@ -264,45 +169,6 @@ fn sample_shadow_map(light_local: vec2, depth: f32, array_index: i32, texel #endif } -// Samples the shadow map for a directional light when percentage-closer soft -// shadows are being used. -// -// We first search for a *blocker*, which is the average depth value of any -// shadow map samples that are adjacent to the sample we're considering. That -// allows us to determine the penumbra size; a larger gap between the blocker -// and the depth of this sample results in a wider penumbra. Finally, we sample -// the shadow map the same way we do in PCF, using that penumbra width. -// -// A good overview of the technique: -// -fn sample_shadow_map_pcss( - light_local: vec2, - depth: f32, - array_index: i32, - texel_size: f32, - light_size: f32, -) -> f32 { - // Determine the average Z value of the closest blocker. - let z_blocker = search_for_blockers_in_shadow_map( - light_local, depth, array_index, texel_size, light_size); - - // Don't let the blur size go below 0.5, or shadows will look unacceptably aliased. - let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); - - // FIXME: We can't use Castano '13 here because that has a hard-wired fixed - // size. So we instead use Jimenez '14 unconditionally. In the non-temporal - // variant this is unfortunately rather noisy. This may be improvable in the - // future by generating a mip chain of the shadow map and using that to - // provide better blurs. -#ifdef SHADOW_FILTER_METHOD_TEMPORAL - return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, blur_size, true); -#else // SHADOW_FILTER_METHOD_TEMPORAL - return sample_shadow_map_jimenez_fourteen( - light_local, depth, array_index, texel_size, blur_size, false); -#endif // SHADOW_FILTER_METHOD_TEMPORAL -} - // NOTE: Due to the non-uniform control flow in `shadows::fetch_point_shadow`, // we must use the Level variant of textureSampleCompare to avoid undefined // behavior due to some of the fragments in a quad (2x2 fragments) being @@ -310,54 +176,10 @@ fn sample_shadow_map_pcss( // The shadow maps have no mipmaps so Level just samples from LOD 0. fn sample_shadow_cubemap_hardware(light_local: vec3, depth: f32, light_id: u32) -> f32 { #ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT - return textureSampleCompare( - view_bindings::point_shadow_textures, - view_bindings::point_shadow_textures_comparison_sampler, - light_local, - depth - ); -#else - return textureSampleCompareLevel( - view_bindings::point_shadow_textures, - view_bindings::point_shadow_textures_comparison_sampler, - light_local, - i32(light_id), - depth - ); -#endif -} - -// Performs one sample of the blocker search. This variation of the blocker -// search function is for point and spot lights. -fn search_for_blockers_in_shadow_cubemap_hardware( - light_local: vec3, - depth: f32, - light_id: u32, -) -> vec2 { -#ifdef WEBGL2 - // Make sure that the WebGL 2 compiler doesn't see `sampled_depth` sampled - // with different samplers, or it'll blow up. - return vec2(0.0); -#else // WEBGL2 - -#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT - let sampled_depth = textureSample( - view_bindings::point_shadow_textures, - view_bindings::point_shadow_textures_linear_sampler, - light_local, - ); + return textureSampleCompare(view_bindings::point_shadow_textures, view_bindings::point_shadow_textures_sampler, light_local, depth); #else - let sampled_depth = textureSample( - view_bindings::point_shadow_textures, - view_bindings::point_shadow_textures_linear_sampler, - light_local, - i32(light_id), - ); + return textureSampleCompareLevel(view_bindings::point_shadow_textures, view_bindings::point_shadow_textures_sampler, light_local, i32(light_id), depth); #endif - - return select(vec2(0.0), vec2(sampled_depth, 1.0), sampled_depth >= depth); - -#endif // WEBGL2 } fn sample_shadow_cubemap_at_offset( @@ -376,26 +198,6 @@ fn sample_shadow_cubemap_at_offset( ) * coeff; } -// Computes the search position and performs one sample of the blocker search. -// This variation of the blocker search function is for point and spot lights. -// -// `x_basis`, `y_basis`, and `light_local` form an orthonormal basis over which -// the blocker search happens. -fn search_for_blockers_in_shadow_cubemap_at_offset( - position: vec2, - x_basis: vec3, - y_basis: vec3, - light_local: vec3, - depth: f32, - light_id: u32, -) -> vec2 { - return search_for_blockers_in_shadow_cubemap_hardware( - light_local + position.x * x_basis + position.y * y_basis, - depth, - light_id - ); -} - // This more or less does what Castano13 does, but in 3D space. Castano13 is // essentially an optimized 2D Gaussian filter that takes advantage of the // bilinear filtering hardware to reduce the number of samples needed. This @@ -447,13 +249,12 @@ fn sample_shadow_cubemap_gaussian( // This is a port of the Jimenez14 filter above to the 3D space. It jitters the // points in the spiral pattern after first creating a 2D orthonormal basis // along the principal light direction. -fn sample_shadow_cubemap_jittered( +fn sample_shadow_cubemap_temporal( light_local: vec3, depth: f32, scale: f32, distance_to_light: f32, light_id: u32, - temporal: bool, ) -> f32 { // Create an orthonormal basis so we can apply a 2D sampling pattern to a // cubemap. @@ -463,7 +264,7 @@ fn sample_shadow_cubemap_jittered( } let basis = orthonormalize(light_local, up) * scale * distance_to_light; - let rotation_matrix = random_rotation_matrix(vec2(1.0), temporal); + let rotation_matrix = random_rotation_matrix(vec2(1.0)); let sample_offset0 = rotation_matrix * utils::SPIRAL_OFFSET_0_ * POINT_SHADOW_TEMPORAL_OFFSET_SCALE; @@ -512,8 +313,8 @@ fn sample_shadow_cubemap( return sample_shadow_cubemap_gaussian( light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id); #else ifdef SHADOW_FILTER_METHOD_TEMPORAL - return sample_shadow_cubemap_jittered( - light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id, true); + return sample_shadow_cubemap_temporal( + light_local, depth, POINT_SHADOW_SCALE, distance_to_light, light_id); #else ifdef SHADOW_FILTER_METHOD_HARDWARE_2X2 return sample_shadow_cubemap_hardware(light_local, depth, light_id); #else @@ -524,76 +325,3 @@ fn sample_shadow_cubemap( return 0.0; #endif } - -// Searches for PCSS blockers in a cubemap. This is the variant of the blocker -// search used for point and spot lights. -// -// This follows the logic in `sample_shadow_cubemap_gaussian`, but uses linear -// sampling instead of percentage-closer filtering. -// -// The `scale` parameter represents the size of the light. -fn search_for_blockers_in_shadow_cubemap( - light_local: vec3, - depth: f32, - scale: f32, - distance_to_light: f32, - light_id: u32, -) -> f32 { - // Create an orthonormal basis so we can apply a 2D sampling pattern to a - // cubemap. - var up = vec3(0.0, 1.0, 0.0); - if (dot(up, normalize(light_local)) > 0.99) { - up = vec3(1.0, 0.0, 0.0); // Avoid creating a degenerate basis. - } - let basis = orthonormalize(light_local, up) * scale * distance_to_light; - - var sum: vec2 = vec2(0.0); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[0], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[1], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[2], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[3], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[4], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[5], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[6], basis[0], basis[1], light_local, depth, light_id); - sum += search_for_blockers_in_shadow_cubemap_at_offset( - D3D_SAMPLE_POINT_POSITIONS[7], basis[0], basis[1], light_local, depth, light_id); - - if (sum.y == 0.0) { - return 0.0; - } - return sum.x / sum.y; -} - -// Samples the shadow map for a point or spot light when percentage-closer soft -// shadows are being used. -// -// A good overview of the technique: -// -fn sample_shadow_cubemap_pcss( - light_local: vec3, - distance_to_light: f32, - depth: f32, - light_id: u32, - light_size: f32, -) -> f32 { - let z_blocker = search_for_blockers_in_shadow_cubemap( - light_local, depth, light_size, distance_to_light, light_id); - - // Don't let the blur size go below 0.5, or shadows will look unacceptably aliased. - let blur_size = max((z_blocker - depth) * light_size / depth, 0.5); - -#ifdef SHADOW_FILTER_METHOD_TEMPORAL - return sample_shadow_cubemap_jittered( - light_local, depth, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, true); -#else - return sample_shadow_cubemap_jittered( - light_local, depth, POINT_SHADOW_SCALE * blur_size, distance_to_light, light_id, false); -#endif -} diff --git a/crates/bevy_pbr/src/render/shadows.wgsl b/crates/bevy_pbr/src/render/shadows.wgsl index 0e539f00091c5..110d8c7fff828 100644 --- a/crates/bevy_pbr/src/render/shadows.wgsl +++ b/crates/bevy_pbr/src/render/shadows.wgsl @@ -3,10 +3,7 @@ #import bevy_pbr::{ mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, mesh_view_bindings as view_bindings, - shadow_sampling::{ - SPOT_SHADOW_TEXEL_SIZE, sample_shadow_cubemap, sample_shadow_cubemap_pcss, - sample_shadow_map, sample_shadow_map_pcss, - } + shadow_sampling::{SPOT_SHADOW_TEXEL_SIZE, sample_shadow_cubemap, sample_shadow_map} } #import bevy_render::{ @@ -44,30 +41,12 @@ fn fetch_point_shadow(light_id: u32, frag_position: vec4, surface_normal: v let zw = -major_axis_magnitude * (*light).light_custom_data.xy + (*light).light_custom_data.zw; let depth = zw.x / zw.y; - // If soft shadows are enabled, use the PCSS path. Cubemaps assume a - // left-handed coordinate space, so we have to flip the z-axis when - // sampling. - if ((*light).soft_shadow_size > 0.0) { - return sample_shadow_cubemap_pcss( - frag_ls * flip_z, - distance_to_light, - depth, - light_id, - (*light).soft_shadow_size, - ); - } - - // Do the lookup, using HW PCF and comparison. Cubemaps assume a left-handed - // coordinate space, so we have to flip the z-axis when sampling. + // Do the lookup, using HW PCF and comparison. Cubemaps assume a left-handed coordinate space, + // so we have to flip the z-axis when sampling. return sample_shadow_cubemap(frag_ls * flip_z, distance_to_light, depth, light_id); } -fn fetch_spot_shadow( - light_id: u32, - frag_position: vec4, - surface_normal: vec3, - near_z: f32, -) -> f32 { +fn fetch_spot_shadow(light_id: u32, frag_position: vec4, surface_normal: vec3) -> f32 { let light = &view_bindings::clusterable_objects.data[light_id]; let surface_to_light = (*light).position_radius.xyz - frag_position.xyz; @@ -112,16 +91,15 @@ fn fetch_spot_shadow( // convert to uv coordinates let shadow_uv = shadow_xy_ndc * vec2(0.5, -0.5) + vec2(0.5, 0.5); - let depth = near_z / -projected_position.z; - - // If soft shadows are enabled, use the PCSS path. - let array_index = i32(light_id) + view_bindings::lights.spot_light_shadowmap_offset; - if ((*light).soft_shadow_size > 0.0) { - return sample_shadow_map_pcss( - shadow_uv, depth, array_index, SPOT_SHADOW_TEXEL_SIZE, (*light).soft_shadow_size); - } + // 0.1 must match POINT_LIGHT_NEAR_Z + let depth = 0.1 / -projected_position.z; - return sample_shadow_map(shadow_uv, depth, array_index, SPOT_SHADOW_TEXEL_SIZE); + return sample_shadow_map( + shadow_uv, + depth, + i32(light_id) + view_bindings::lights.spot_light_shadowmap_offset, + SPOT_SHADOW_TEXEL_SIZE + ); } fn get_cascade_index(light_id: u32, view_z: f32) -> u32 { @@ -168,12 +146,7 @@ fn world_to_directional_light_local( return vec4(light_local, depth, 1.0); } -fn sample_directional_cascade( - light_id: u32, - cascade_index: u32, - frag_position: vec4, - surface_normal: vec3, -) -> f32 { +fn sample_directional_cascade(light_id: u32, cascade_index: u32, frag_position: vec4, surface_normal: vec3) -> f32 { let light = &view_bindings::lights.directional_lights[light_id]; let cascade = &(*light).cascades[cascade_index]; @@ -188,15 +161,7 @@ fn sample_directional_cascade( } let array_index = i32((*light).depth_texture_base_index + cascade_index); - let texel_size = (*cascade).texel_size; - - // If soft shadows are enabled, use the PCSS path. - if ((*light).soft_shadow_size > 0.0) { - return sample_shadow_map_pcss( - light_local.xy, light_local.z, array_index, texel_size, (*light).soft_shadow_size); - } - - return sample_shadow_map(light_local.xy, light_local.z, array_index, texel_size); + return sample_shadow_map(light_local.xy, light_local.z, array_index, (*cascade).texel_size); } fn fetch_directional_shadow(light_id: u32, frag_position: vec4, surface_normal: vec3, view_z: f32) -> f32 { diff --git a/examples/3d/pcss.rs b/examples/3d/pcss.rs deleted file mode 100644 index f99cb465163dc..0000000000000 --- a/examples/3d/pcss.rs +++ /dev/null @@ -1,417 +0,0 @@ -//! Demonstrates percentage-closer soft shadows (PCSS). - -use std::f32::consts::PI; - -use bevy::{ - core_pipeline::{ - experimental::taa::{TemporalAntiAliasPlugin, TemporalAntiAliasing}, - prepass::{DepthPrepass, MotionVectorPrepass}, - Skybox, - }, - math::vec3, - pbr::{CubemapVisibleEntities, ShadowFilteringMethod, VisibleMeshEntities}, - prelude::*, - render::{ - camera::TemporalJitter, - primitives::{CubemapFrusta, Frustum}, - }, -}; - -use crate::widgets::{RadioButton, RadioButtonText, WidgetClickEvent, WidgetClickSender}; - -#[path = "../helpers/widgets.rs"] -mod widgets; - -/// The size of the light, which affects the size of the penumbras. -const LIGHT_RADIUS: f32 = 10.0; - -/// The intensity of the point and spot lights. -const POINT_LIGHT_INTENSITY: f32 = 1_000_000_000.0; - -/// The range in meters of the point and spot lights. -const POINT_LIGHT_RANGE: f32 = 110.0; - -/// The depth bias for directional and spot lights. This value is set higher -/// than the default to avoid shadow acne. -const DIRECTIONAL_SHADOW_DEPTH_BIAS: f32 = 0.20; - -/// The depth bias for point lights. This value is set higher than the default to -/// avoid shadow acne. -/// -/// Unfortunately, there is a bit of Peter Panning with this value, because of -/// the distance and angle of the light. This can't be helped in this scene -/// without increasing the shadow map size beyond reasonable limits. -const POINT_SHADOW_DEPTH_BIAS: f32 = 0.35; - -/// The near Z value for the shadow map, in meters. This is set higher than the -/// default in order to achieve greater resolution in the shadow map for point -/// and spot lights. -const SHADOW_MAP_NEAR_Z: f32 = 50.0; - -/// The current application settings (light type, shadow filter, and the status -/// of PCSS). -#[derive(Resource)] -struct AppStatus { - /// The type of light presently in the scene: either directional or point. - light_type: LightType, - /// The type of shadow filter: Gaussian or temporal. - shadow_filter: ShadowFilter, - /// Whether soft shadows are enabled. - soft_shadows: bool, -} - -impl Default for AppStatus { - fn default() -> Self { - Self { - light_type: default(), - shadow_filter: default(), - soft_shadows: true, - } - } -} - -/// The type of light presently in the scene: directional, point, or spot. -#[derive(Clone, Copy, Default, PartialEq)] -enum LightType { - /// A directional light, with a cascaded shadow map. - #[default] - Directional, - /// A point light, with a cube shadow map. - Point, - /// A spot light, with a cube shadow map. - Spot, -} - -/// The type of shadow filter. -/// -/// Generally, `Gaussian` is preferred when temporal antialiasing isn't in use, -/// while `Temporal` is preferred when TAA is in use. In this example, this -/// setting also turns TAA on and off. -#[derive(Clone, Copy, Default, PartialEq)] -enum ShadowFilter { - /// The non-temporal Gaussian filter (Castano '13 for directional lights, an - /// analogous alternative for point and spot lights). - #[default] - NonTemporal, - /// The temporal Gaussian filter (Jimenez '14 for directional lights, an - /// analogous alternative for point and spot lights). - Temporal, -} - -/// Each example setting that can be toggled in the UI. -#[derive(Clone, Copy, PartialEq)] -enum AppSetting { - /// The type of light presently in the scene: directional, point, or spot. - LightType(LightType), - /// The type of shadow filter. - ShadowFilter(ShadowFilter), - /// Whether PCSS is enabled or disabled. - SoftShadows(bool), -} - -/// The example application entry point. -fn main() { - App::new() - .init_resource::() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "Bevy Percentage Closer Soft Shadows Example".into(), - ..default() - }), - ..default() - })) - .add_plugins(TemporalAntiAliasPlugin) - .add_event::>() - .add_systems(Startup, setup) - .add_systems(Update, widgets::handle_ui_interactions::) - .add_systems( - Update, - update_radio_buttons.after(widgets::handle_ui_interactions::), - ) - .add_systems( - Update, - ( - handle_light_type_change, - handle_shadow_filter_change, - handle_pcss_toggle, - ) - .after(widgets::handle_ui_interactions::), - ) - .run(); -} - -/// Creates all the objects in the scene. -fn setup(mut commands: Commands, asset_server: Res, app_status: Res) { - spawn_camera(&mut commands, &asset_server); - spawn_light(&mut commands, &app_status); - spawn_gltf_scene(&mut commands, &asset_server); - spawn_buttons(&mut commands); -} - -/// Spawns the camera, with the initial shadow filtering method. -fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) { - commands - .spawn(Camera3dBundle { - transform: Transform::from_xyz(-12.912 * 0.7, 4.466 * 0.7, -10.624 * 0.7) - .with_rotation(Quat::from_euler( - EulerRot::YXZ, - -134.76 / 180.0 * PI, - -0.175, - 0.0, - )), - ..default() - }) - .insert(ShadowFilteringMethod::Gaussian) - // `TemporalJitter` is needed for TAA. Note that it does nothing without - // `TemporalAntiAliasSettings`. - .insert(TemporalJitter::default()) - // We want MSAA off for TAA to work properly. - .insert(Msaa::Off) - // The depth prepass is needed for TAA. - .insert(DepthPrepass) - // The motion vector prepass is needed for TAA. - .insert(MotionVectorPrepass) - // Add a nice skybox. - .insert(Skybox { - image: asset_server.load("environment_maps/sky_skybox.ktx2"), - brightness: 500.0, - rotation: Quat::IDENTITY, - }); -} - -/// Spawns the initial light. -fn spawn_light(commands: &mut Commands, app_status: &AppStatus) { - // Because this light can become a directional light, point light, or spot - // light depending on the settings, we add the union of the components - // necessary for this light to behave as all three of those. - commands - .spawn(DirectionalLightBundle { - directional_light: create_directional_light(app_status), - transform: Transform::from_rotation(Quat::from_array([ - 0.6539259, - -0.34646285, - 0.36505926, - -0.5648683, - ])) - .with_translation(vec3(57.693, 34.334, -6.422)), - ..default() - }) - // These two are needed for point lights. - .insert(CubemapVisibleEntities::default()) - .insert(CubemapFrusta::default()) - // These two are needed for spot lights. - .insert(VisibleMeshEntities::default()) - .insert(Frustum::default()); -} - -/// Loads and spawns the glTF palm tree scene. -fn spawn_gltf_scene(commands: &mut Commands, asset_server: &AssetServer) { - commands.spawn(SceneBundle { - scene: asset_server.load("models/PalmTree/PalmTree.gltf#Scene0"), - ..default() - }); -} - -/// Spawns all the buttons at the bottom of the screen. -fn spawn_buttons(commands: &mut Commands) { - commands - .spawn(NodeBundle { - style: widgets::main_ui_style(), - ..default() - }) - .with_children(|parent| { - widgets::spawn_option_buttons( - parent, - "Light Type", - &[ - (AppSetting::LightType(LightType::Directional), "Directional"), - (AppSetting::LightType(LightType::Point), "Point"), - (AppSetting::LightType(LightType::Spot), "Spot"), - ], - ); - widgets::spawn_option_buttons( - parent, - "Shadow Filter", - &[ - (AppSetting::ShadowFilter(ShadowFilter::Temporal), "Temporal"), - ( - AppSetting::ShadowFilter(ShadowFilter::NonTemporal), - "Non-Temporal", - ), - ], - ); - widgets::spawn_option_buttons( - parent, - "Soft Shadows", - &[ - (AppSetting::SoftShadows(true), "On"), - (AppSetting::SoftShadows(false), "Off"), - ], - ); - }); -} - -/// Updates the style of the radio buttons that enable and disable soft shadows -/// to reflect whether PCSS is enabled. -fn update_radio_buttons( - mut widgets: Query< - ( - Option<&mut BackgroundColor>, - Option<&mut Text>, - &WidgetClickSender, - ), - Or<(With, With)>, - >, - app_status: Res, -) { - for (image, text, sender) in widgets.iter_mut() { - let selected = match **sender { - AppSetting::LightType(light_type) => light_type == app_status.light_type, - AppSetting::ShadowFilter(shadow_filter) => shadow_filter == app_status.shadow_filter, - AppSetting::SoftShadows(soft_shadows) => soft_shadows == app_status.soft_shadows, - }; - - if let Some(mut bg_color) = image { - widgets::update_ui_radio_button(&mut bg_color, selected); - } - if let Some(mut text) = text { - widgets::update_ui_radio_button_text(&mut text, selected); - } - } -} - -/// Handles requests from the user to change the type of light. -fn handle_light_type_change( - mut commands: Commands, - mut lights: Query, With, With)>>, - mut events: EventReader>, - mut app_status: ResMut, -) { - for event in events.read() { - let AppSetting::LightType(light_type) = **event else { - continue; - }; - app_status.light_type = light_type; - - for light in lights.iter_mut() { - let light_commands = commands - .entity(light) - .remove::() - .remove::() - .remove::(); - match light_type { - LightType::Point => { - light_commands.insert(create_point_light(&app_status)); - } - LightType::Spot => { - light_commands.insert(create_spot_light(&app_status)); - } - LightType::Directional => { - light_commands.insert(create_directional_light(&app_status)); - } - } - } - } -} - -/// Handles requests from the user to change the shadow filter method. -/// -/// This system is also responsible for enabling and disabling TAA as -/// appropriate. -fn handle_shadow_filter_change( - mut commands: Commands, - mut cameras: Query<(Entity, &mut ShadowFilteringMethod)>, - mut events: EventReader>, - mut app_status: ResMut, -) { - for event in events.read() { - let AppSetting::ShadowFilter(shadow_filter) = **event else { - continue; - }; - app_status.shadow_filter = shadow_filter; - - for (camera, mut shadow_filtering_method) in cameras.iter_mut() { - match shadow_filter { - ShadowFilter::NonTemporal => { - *shadow_filtering_method = ShadowFilteringMethod::Gaussian; - commands.entity(camera).remove::(); - } - ShadowFilter::Temporal => { - *shadow_filtering_method = ShadowFilteringMethod::Temporal; - commands - .entity(camera) - .insert(TemporalAntiAliasing::default()); - } - } - } - } -} - -/// Handles requests from the user to toggle soft shadows on and off. -fn handle_pcss_toggle( - mut lights: Query>, - mut events: EventReader>, - mut app_status: ResMut, -) { - for event in events.read() { - let AppSetting::SoftShadows(value) = **event else { - continue; - }; - app_status.soft_shadows = value; - - // Recreating the lights is the simplest way to toggle soft shadows. - for (directional_light, point_light, spot_light) in lights.iter_mut() { - if let Some(mut directional_light) = directional_light { - *directional_light = create_directional_light(&app_status); - } - if let Some(mut point_light) = point_light { - *point_light = create_point_light(&app_status); - } - if let Some(mut spot_light) = spot_light { - *spot_light = create_spot_light(&app_status); - } - } - } -} - -/// Creates the [`DirectionalLight`] component with the appropriate settings. -fn create_directional_light(app_status: &AppStatus) -> DirectionalLight { - DirectionalLight { - shadows_enabled: true, - soft_shadow_size: if app_status.soft_shadows { - Some(LIGHT_RADIUS) - } else { - None - }, - shadow_depth_bias: DIRECTIONAL_SHADOW_DEPTH_BIAS, - ..default() - } -} - -/// Creates the [`PointLight`] component with the appropriate settings. -fn create_point_light(app_status: &AppStatus) -> PointLight { - PointLight { - intensity: POINT_LIGHT_INTENSITY, - range: POINT_LIGHT_RANGE, - shadows_enabled: true, - radius: LIGHT_RADIUS, - soft_shadows_enabled: app_status.soft_shadows, - shadow_depth_bias: POINT_SHADOW_DEPTH_BIAS, - shadow_map_near_z: SHADOW_MAP_NEAR_Z, - ..default() - } -} - -/// Creates the [`SpotLight`] component with the appropriate settings. -fn create_spot_light(app_status: &AppStatus) -> SpotLight { - SpotLight { - intensity: POINT_LIGHT_INTENSITY, - range: POINT_LIGHT_RANGE, - radius: LIGHT_RADIUS, - shadows_enabled: true, - soft_shadows_enabled: app_status.soft_shadows, - shadow_depth_bias: DIRECTIONAL_SHADOW_DEPTH_BIAS, - shadow_map_near_z: SHADOW_MAP_NEAR_Z, - ..default() - } -} diff --git a/examples/README.md b/examples/README.md index 83229d04e60e3..cc06a7e286416 100644 --- a/examples/README.md +++ b/examples/README.md @@ -156,7 +156,6 @@ Example | Description [Orthographic View](../examples/3d/orthographic.rs) | Shows how to create a 3D orthographic view (for isometric-look in games or CAD applications) [Parallax Mapping](../examples/3d/parallax_mapping.rs) | Demonstrates use of a normal map and depth map for parallax mapping [Parenting](../examples/3d/parenting.rs) | Demonstrates parent->child relationships and relative transformations -[Percentage-closer soft shadows](../examples/3d/pcss.rs) | Demonstrates percentage-closer soft shadows (PCSS) [Physically Based Rendering](../examples/3d/pbr.rs) | Demonstrates use of Physically Based Rendering (PBR) properties [Reflection Probes](../examples/3d/reflection_probes.rs) | Demonstrates reflection probes [Render to Texture](../examples/3d/render_to_texture.rs) | Shows how to render to a texture, useful for mirrors, UI, or exporting images diff --git a/examples/helpers/widgets.rs b/examples/helpers/widgets.rs deleted file mode 100644 index 1c1a2aae9e3ec..0000000000000 --- a/examples/helpers/widgets.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Simple widgets for example UI. - -use bevy::{ecs::system::EntityCommands, prelude::*}; - -/// An event that's sent whenever the user changes one of the settings by -/// clicking a radio button. -#[derive(Clone, Event, Deref, DerefMut)] -pub struct WidgetClickEvent(T); - -/// A marker component that we place on all widgets that send -/// [`WidgetClickEvent`]s of the given type. -#[derive(Clone, Component, Deref, DerefMut)] -pub struct WidgetClickSender(T) -where - T: Clone + Send + Sync + 'static; - -/// A marker component that we place on all radio `Button`s. -#[derive(Clone, Copy, Component)] -pub struct RadioButton; - -/// A marker component that we place on all `Text` inside radio buttons. -#[derive(Clone, Copy, Component)] -pub struct RadioButtonText; - -/// Returns a [`Style`] appropriate for the outer main UI node. -/// -/// This UI is in the bottom left corner and has flex column support -pub fn main_ui_style() -> Style { - Style { - flex_direction: FlexDirection::Column, - position_type: PositionType::Absolute, - row_gap: Val::Px(6.0), - left: Val::Px(10.0), - bottom: Val::Px(10.0), - ..default() - } -} - -/// Spawns a single radio button that allows configuration of a setting. -/// -/// The type parameter specifies the value that will be packaged up and sent in -/// a [`WidgetClickEvent`] when the radio button is clicked. -pub fn spawn_option_button( - parent: &mut ChildBuilder, - option_value: T, - option_name: &str, - is_selected: bool, - is_first: bool, - is_last: bool, -) where - T: Clone + Send + Sync + 'static, -{ - let (bg_color, fg_color) = if is_selected { - (Color::WHITE, Color::BLACK) - } else { - (Color::BLACK, Color::WHITE) - }; - - // Add the button node. - parent - .spawn(ButtonBundle { - style: Style { - border: UiRect::all(Val::Px(1.0)).with_left(if is_first { - Val::Px(1.0) - } else { - Val::Px(0.0) - }), - justify_content: JustifyContent::Center, - align_items: AlignItems::Center, - padding: UiRect::axes(Val::Px(12.0), Val::Px(6.0)), - ..default() - }, - border_color: BorderColor(Color::WHITE), - border_radius: BorderRadius::ZERO - .with_left(if is_first { Val::Px(6.0) } else { Val::Px(0.0) }) - .with_right(if is_last { Val::Px(6.0) } else { Val::Px(0.0) }), - background_color: BackgroundColor(bg_color), - ..default() - }) - .insert(RadioButton) - .insert(WidgetClickSender(option_value.clone())) - .with_children(|parent| { - spawn_ui_text(parent, option_name, fg_color) - .insert(RadioButtonText) - .insert(WidgetClickSender(option_value)); - }); -} - -/// Spawns the buttons that allow configuration of a setting. -/// -/// The user may change the setting to any one of the labeled `options`. The -/// value of the given type parameter will be packaged up and sent as a -/// [`WidgetClickEvent`] when one of the radio buttons is clicked. -pub fn spawn_option_buttons(parent: &mut ChildBuilder, title: &str, options: &[(T, &str)]) -where - T: Clone + Send + Sync + 'static, -{ - // Add the parent node for the row. - parent - .spawn(NodeBundle { - style: Style { - align_items: AlignItems::Center, - ..default() - }, - ..default() - }) - .with_children(|parent| { - spawn_ui_text(parent, title, Color::BLACK).insert(Style { - width: Val::Px(125.0), - ..default() - }); - - for (option_index, (option_value, option_name)) in options.iter().cloned().enumerate() { - spawn_option_button( - parent, - option_value, - option_name, - option_index == 0, - option_index == 0, - option_index == options.len() - 1, - ); - } - }); -} - -/// Spawns text for the UI. -/// -/// Returns the `EntityCommands`, which allow further customization of the text -/// style. -pub fn spawn_ui_text<'a>( - parent: &'a mut ChildBuilder, - label: &str, - color: Color, -) -> EntityCommands<'a> { - parent.spawn(TextBundle::from_section( - label, - TextStyle { - font_size: 18.0, - color, - ..default() - }, - )) -} - -/// Checks for clicks on the radio buttons and sends `RadioButtonChangeEvent`s -/// as necessary. -pub fn handle_ui_interactions( - mut interactions: Query< - (&Interaction, &WidgetClickSender), - (With