From 537adcc3f74964db745a45630ed9a6d48b617f51 Mon Sep 17 00:00:00 2001 From: atlv Date: Sun, 6 Jul 2025 20:07:38 -0400 Subject: [PATCH] bevy_light (#19991) # Objective - make lights usable without bevy_render ## Solution - make a new crate for lights to live in ## Testing - 3d_scene, lighting, volumetric_fog, ssr, transmission, pcss, light_textures Note: no breaking changes because of re-exports, except for light textures, which were introduced this cycle so it doesn't matter anyways --- crates/bevy_light/Cargo.toml | 44 +++++ crates/bevy_light/LICENSE-APACHE | 176 ++++++++++++++++++ crates/bevy_light/LICENSE-MIT | 19 ++ .../light => bevy_light/src}/ambient_light.rs | 5 +- .../src/light => bevy_light/src}/cascade.rs | 4 +- .../src/cluster/assign.rs | 26 +-- .../src/cluster/mod.rs | 35 ++-- .../src/cluster/test.rs | 2 +- .../src}/directional_light.rs | 7 +- .../light/mod.rs => bevy_light/src/lib.rs} | 38 ++-- .../light => bevy_light/src}/point_light.rs | 2 +- crates/bevy_light/src/probe.rs | 109 +++++++++++ .../light => bevy_light/src}/spot_light.rs | 3 +- crates/bevy_light/src/volumetric.rs | 157 ++++++++++++++++ crates/bevy_pbr/Cargo.toml | 7 +- .../extract_and_prepare.rs => cluster.rs} | 2 +- crates/bevy_pbr/src/decal/clustered.rs | 4 +- crates/bevy_pbr/src/deferred/mod.rs | 12 +- crates/bevy_pbr/src/lib.rs | 22 ++- .../src/light_probe/environment_map.rs | 59 +----- .../src/light_probe/irradiance_volume.rs | 3 +- crates/bevy_pbr/src/light_probe/mod.rs | 63 +------ .../src/meshlet/material_pipeline_prepare.rs | 3 +- crates/bevy_pbr/src/render/light.rs | 27 ++- crates/bevy_pbr/src/render/mesh.rs | 4 +- .../bevy_pbr/src/render/mesh_view_bindings.rs | 2 +- crates/bevy_pbr/src/volumetric_fog/mod.rs | 172 +---------------- crates/bevy_render/Cargo.toml | 1 + crates/bevy_render/src/extract_impls.rs | 41 ++++ crates/bevy_render/src/lib.rs | 1 + examples/3d/light_textures.rs | 8 +- .../reduce-light-cluster-config.patch | 6 +- 32 files changed, 678 insertions(+), 386 deletions(-) create mode 100644 crates/bevy_light/Cargo.toml create mode 100644 crates/bevy_light/LICENSE-APACHE create mode 100644 crates/bevy_light/LICENSE-MIT rename crates/{bevy_pbr/src/light => bevy_light/src}/ambient_light.rs (89%) rename crates/{bevy_pbr/src/light => bevy_light/src}/cascade.rs (99%) rename crates/{bevy_pbr => bevy_light}/src/cluster/assign.rs (98%) rename crates/{bevy_pbr => bevy_light}/src/cluster/mod.rs (94%) rename crates/{bevy_pbr => bevy_light}/src/cluster/test.rs (98%) rename crates/{bevy_pbr/src/light => bevy_light/src}/directional_light.rs (98%) rename crates/{bevy_pbr/src/light/mod.rs => bevy_light/src/lib.rs} (96%) rename crates/{bevy_pbr/src/light => bevy_light/src}/point_light.rs (99%) create mode 100644 crates/bevy_light/src/probe.rs rename crates/{bevy_pbr/src/light => bevy_light/src}/spot_light.rs (99%) create mode 100644 crates/bevy_light/src/volumetric.rs rename crates/bevy_pbr/src/{cluster/extract_and_prepare.rs => cluster.rs} (99%) create mode 100644 crates/bevy_render/src/extract_impls.rs diff --git a/crates/bevy_light/Cargo.toml b/crates/bevy_light/Cargo.toml new file mode 100644 index 0000000000..0dd7e158c8 --- /dev/null +++ b/crates/bevy_light/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "bevy_light" +version = "0.17.0-dev" +edition = "2024" +description = "Keeps the lights on at Bevy Engine" +homepage = "https://bevy.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[dependencies] +# bevy +bevy_app = { path = "../bevy_app", version = "0.17.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" } +bevy_image = { path = "../bevy_image", version = "0.17.0-dev" } +bevy_mesh = { path = "../bevy_mesh", version = "0.17.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.17.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" } +bevy_camera = { path = "../bevy_camera", version = "0.17.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" } +bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev" } +bevy_color = { path = "../bevy_color", version = "0.17.0-dev", features = [ + "serialize", +] } + +# other +serde = { version = "1", default-features = false, features = ["derive"] } +tracing = { version = "0.1", default-features = false } + +[features] +default = [] +experimental_pbr_pcss = [] +webgl = [] +webgpu = [] + +[lints] +workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"] +all-features = true diff --git a/crates/bevy_light/LICENSE-APACHE b/crates/bevy_light/LICENSE-APACHE new file mode 100644 index 0000000000..d9a10c0d8e --- /dev/null +++ b/crates/bevy_light/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/crates/bevy_light/LICENSE-MIT b/crates/bevy_light/LICENSE-MIT new file mode 100644 index 0000000000..9cf106272a --- /dev/null +++ b/crates/bevy_light/LICENSE-MIT @@ -0,0 +1,19 @@ +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/bevy_pbr/src/light/ambient_light.rs b/crates/bevy_light/src/ambient_light.rs similarity index 89% rename from crates/bevy_pbr/src/light/ambient_light.rs rename to crates/bevy_light/src/ambient_light.rs index dfb9cdfecc..92935e7e06 100644 --- a/crates/bevy_pbr/src/light/ambient_light.rs +++ b/crates/bevy_light/src/ambient_light.rs @@ -2,7 +2,6 @@ use bevy_camera::Camera; use bevy_color::Color; use bevy_ecs::prelude::*; use bevy_reflect::prelude::*; -use bevy_render::{extract_component::ExtractComponent, extract_resource::ExtractResource}; /// An ambient light, which lights the entire scene equally. /// @@ -16,14 +15,14 @@ use bevy_render::{extract_component::ExtractComponent, extract_resource::Extract /// /// ``` /// # use bevy_ecs::system::ResMut; -/// # use bevy_pbr::AmbientLight; +/// # use bevy_light::AmbientLight; /// fn setup_ambient_light(mut ambient_light: ResMut) { /// ambient_light.brightness = 100.0; /// } /// ``` /// /// [`LightPlugin`]: crate::LightPlugin -#[derive(Resource, Component, Clone, Debug, ExtractResource, ExtractComponent, Reflect)] +#[derive(Resource, Component, Clone, Debug, Reflect)] #[reflect(Resource, Component, Debug, Default, Clone)] #[require(Camera)] pub struct AmbientLight { diff --git a/crates/bevy_pbr/src/light/cascade.rs b/crates/bevy_light/src/cascade.rs similarity index 99% rename from crates/bevy_pbr/src/light/cascade.rs rename to crates/bevy_light/src/cascade.rs index a6ebe5a89b..0cb713a9e6 100644 --- a/crates/bevy_pbr/src/light/cascade.rs +++ b/crates/bevy_light/src/cascade.rs @@ -11,8 +11,8 @@ use crate::{DirectionalLight, DirectionalLightShadowMap}; /// Prefer using [`CascadeShadowConfigBuilder`] to construct an instance. /// /// ``` -/// # use bevy_pbr::CascadeShadowConfig; -/// # use bevy_pbr::CascadeShadowConfigBuilder; +/// # use bevy_light::CascadeShadowConfig; +/// # use bevy_light::CascadeShadowConfigBuilder; /// # use bevy_utils::default; /// # /// let config: CascadeShadowConfig = CascadeShadowConfigBuilder { diff --git a/crates/bevy_pbr/src/cluster/assign.rs b/crates/bevy_light/src/cluster/assign.rs similarity index 98% rename from crates/bevy_pbr/src/cluster/assign.rs rename to crates/bevy_light/src/cluster/assign.rs index e204644204..20a40104ed 100644 --- a/crates/bevy_pbr/src/cluster/assign.rs +++ b/crates/bevy_light/src/cluster/assign.rs @@ -22,10 +22,7 @@ use super::{ ClusterConfig, ClusterFarZMode, ClusteredDecal, Clusters, GlobalClusterSettings, GlobalVisibleClusterableObjects, VisibleClusterableObjects, }; -use crate::{ - prelude::EnvironmentMapLight, ExtractedPointLight, LightProbe, PointLight, SpotLight, - VolumetricLight, -}; +use crate::{EnvironmentMapLight, LightProbe, PointLight, SpotLight, VolumetricLight}; const NDC_MIN: Vec2 = Vec2::NEG_ONE; const NDC_MAX: Vec2 = Vec2::ONE; @@ -57,7 +54,7 @@ impl ClusterableObjectAssignmentData { /// Data needed to assign objects to clusters that's specific to the type of /// clusterable object. #[derive(Clone, Copy, Debug)] -pub(crate) enum ClusterableObjectType { +pub enum ClusterableObjectType { /// Data needed to assign point lights to clusters. PointLight { /// Whether shadows are enabled for this point light. @@ -105,7 +102,7 @@ impl ClusterableObjectType { /// Generally, we sort first by type, then, for lights, by whether shadows /// are enabled (enabled before disabled), and then whether volumetrics are /// enabled (enabled before disabled). - pub(crate) fn ordering(&self) -> (u8, bool, bool) { + pub fn ordering(&self) -> (u8, bool, bool) { match *self { ClusterableObjectType::PointLight { shadows_enabled, @@ -121,23 +118,6 @@ impl ClusterableObjectType { ClusterableObjectType::Decal => (4, false, false), } } - - /// Creates the [`ClusterableObjectType`] data for a point or spot light. - pub(crate) fn from_point_or_spot_light( - point_light: &ExtractedPointLight, - ) -> ClusterableObjectType { - match point_light.spot_light_angles { - Some((_, outer_angle)) => ClusterableObjectType::SpotLight { - outer_angle, - shadows_enabled: point_light.shadows_enabled, - volumetric: point_light.volumetric, - }, - None => ClusterableObjectType::PointLight { - shadows_enabled: point_light.shadows_enabled, - volumetric: point_light.volumetric, - }, - } - } } // NOTE: Run this before update_point_light_frusta! diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_light/src/cluster/mod.rs similarity index 94% rename from crates/bevy_pbr/src/cluster/mod.rs rename to crates/bevy_light/src/cluster/mod.rs index 5132326fb1..92f1c5723e 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_light/src/cluster/mod.rs @@ -17,15 +17,10 @@ use bevy_image::Image; use bevy_math::{AspectRatio, UVec2, UVec3, Vec3Swizzles as _}; use bevy_platform::collections::HashSet; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_render::extract_component::ExtractComponent; use bevy_transform::components::Transform; use tracing::warn; -pub(crate) use crate::cluster::assign::assign_objects_to_clusters; - -pub(crate) mod assign; -mod extract_and_prepare; -pub use extract_and_prepare::*; +pub mod assign; #[cfg(test)] mod test; @@ -106,14 +101,14 @@ pub enum ClusterConfig { #[derive(Component, Debug, Default)] pub struct Clusters { /// Tile size - pub(crate) tile_size: UVec2, + pub tile_size: UVec2, /// Number of clusters in `X` / `Y` / `Z` in the view frustum - pub(crate) dimensions: UVec3, + pub dimensions: UVec3, /// Distance to the far plane of the first depth slice. The first depth slice is special /// and explicitly-configured to avoid having unnecessarily many slices close to the camera. - pub(crate) near: f32, - pub(crate) far: f32, - pub(crate) clusterable_objects: Vec, + pub near: f32, + pub far: f32, + pub clusterable_objects: Vec, } /// The [`VisibilityClass`] used for clusterables (decals, point lights, directional lights, and spot lights). @@ -123,8 +118,8 @@ pub struct ClusterVisibilityClass; #[derive(Clone, Component, Debug, Default)] pub struct VisibleClusterableObjects { - pub(crate) entities: Vec, - counts: ClusterableObjectCounts, + pub entities: Vec, + pub counts: ClusterableObjectCounts, } #[derive(Resource, Default)] @@ -137,17 +132,17 @@ pub struct GlobalVisibleClusterableObjects { /// Note that `reflection_probes` and `irradiance_volumes` won't be clustered if /// fewer than 3 SSBOs are available, which usually means on WebGL 2. #[derive(Clone, Copy, Default, Debug)] -struct ClusterableObjectCounts { +pub struct ClusterableObjectCounts { /// The number of point lights in the cluster. - point_lights: u32, + pub point_lights: u32, /// The number of spot lights in the cluster. - spot_lights: u32, + pub spot_lights: u32, /// The number of reflection probes in the cluster. - reflection_probes: u32, + pub reflection_probes: u32, /// The number of irradiance volumes in the cluster. - irradiance_volumes: u32, + pub irradiance_volumes: u32, /// The number of decals in the cluster. - decals: u32, + pub decals: u32, } /// An object that projects a decal onto surfaces within its bounds. @@ -160,7 +155,7 @@ struct ClusterableObjectCounts { /// but they require bindless textures. This means that they presently can't be /// used on WebGL 2, WebGPU, macOS, or iOS. Bevy's clustered decals can be used /// with forward or deferred rendering and don't require a prepass. -#[derive(Component, Debug, Clone, Reflect, ExtractComponent)] +#[derive(Component, Debug, Clone, Reflect)] #[reflect(Component, Debug, Clone)] #[require(Transform, Visibility, VisibilityClass)] #[component(on_add = visibility::add_visibility_class::)] diff --git a/crates/bevy_pbr/src/cluster/test.rs b/crates/bevy_light/src/cluster/test.rs similarity index 98% rename from crates/bevy_pbr/src/cluster/test.rs rename to crates/bevy_light/src/cluster/test.rs index 23809da7f6..4939d9cb74 100644 --- a/crates/bevy_pbr/src/cluster/test.rs +++ b/crates/bevy_light/src/cluster/test.rs @@ -1,6 +1,6 @@ use bevy_math::UVec2; -use crate::{ClusterConfig, Clusters}; +use super::{ClusterConfig, Clusters}; fn test_cluster_tiling(config: ClusterConfig, screen_size: UVec2) -> Clusters { let dims = config.dimensions_for_screen_size(screen_size); diff --git a/crates/bevy_pbr/src/light/directional_light.rs b/crates/bevy_light/src/directional_light.rs similarity index 98% rename from crates/bevy_pbr/src/light/directional_light.rs rename to crates/bevy_light/src/directional_light.rs index 0b54b63cfe..9a13999ccc 100644 --- a/crates/bevy_pbr/src/light/directional_light.rs +++ b/crates/bevy_light/src/directional_light.rs @@ -10,8 +10,9 @@ use bevy_image::Image; use bevy_reflect::prelude::*; use bevy_transform::components::Transform; -use super::{cascade::CascadeShadowConfig, light_consts, Cascades}; -use crate::cluster::ClusterVisibilityClass; +use super::{ + cascade::CascadeShadowConfig, cluster::ClusterVisibilityClass, light_consts, Cascades, +}; /// A Directional light. /// @@ -172,7 +173,7 @@ pub struct DirectionalLightTexture { /// /// ``` /// # use bevy_app::prelude::*; -/// # use bevy_pbr::DirectionalLightShadowMap; +/// # use bevy_light::DirectionalLightShadowMap; /// App::new() /// .insert_resource(DirectionalLightShadowMap { size: 4096 }); /// ``` diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_light/src/lib.rs similarity index 96% rename from crates/bevy_pbr/src/light/mod.rs rename to crates/bevy_light/src/lib.rs index a220b65439..cf7e19ed81 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_light/src/lib.rs @@ -1,3 +1,5 @@ +#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")] + use bevy_app::{App, Plugin, PostUpdate}; use bevy_camera::{ primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, Sphere}, @@ -10,21 +12,27 @@ use bevy_camera::{ }; use bevy_ecs::{entity::EntityHashSet, prelude::*}; use bevy_math::Vec3A; +use bevy_mesh::Mesh3d; use bevy_reflect::prelude::*; -use bevy_render::{extract_component::ExtractComponent, mesh::Mesh3d}; use bevy_transform::{components::GlobalTransform, TransformSystems}; use bevy_utils::Parallel; use core::ops::DerefMut; -use crate::cluster::{add_clusters, assign_objects_to_clusters, VisibleClusterableObjects}; - +pub mod cluster; +pub use cluster::ClusteredDecal; +use cluster::{ + add_clusters, assign::assign_objects_to_clusters, ClusterConfig, + GlobalVisibleClusterableObjects, VisibleClusterableObjects, +}; mod ambient_light; pub use ambient_light::AmbientLight; +mod probe; +pub use probe::{EnvironmentMapLight, LightProbe}; +mod volumetric; +pub use volumetric::{FogVolume, VolumetricFog, VolumetricLight}; pub mod cascade; -use cascade::{ - build_directional_light_cascades, clear_directional_light_cascades, CascadeShadowConfig, - Cascades, -}; +use cascade::{build_directional_light_cascades, clear_directional_light_cascades}; +pub use cascade::{CascadeShadowConfig, CascadeShadowConfigBuilder, Cascades}; mod point_light; pub use point_light::{ update_point_light_frusta, PointLight, PointLightShadowMap, PointLightTexture, @@ -111,9 +119,15 @@ impl Plugin for LightPlugin { .register_type::() .register_type::() .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() .register_type::() .register_type::() .register_type::() + .register_type::() + .init_resource::() .init_resource::() .init_resource::() .init_resource::() @@ -182,7 +196,7 @@ impl Plugin for LightPlugin { } /// A convenient alias for `Or<(With, With, -/// With)>`, for use with [`bevy_render::view::VisibleEntities`]. +/// With)>`, for use with [`bevy_camera::visibility::VisibleEntities`]. pub type WithLight = Or<(With, With, With)>; /// Add this component to make a [`Mesh3d`] not cast shadows. @@ -197,10 +211,10 @@ pub struct NotShadowCaster; #[derive(Debug, Component, Reflect, Default)] #[reflect(Component, Default, Debug)] pub struct NotShadowReceiver; -/// Add this component to make a [`Mesh3d`] using a PBR material with [`diffuse_transmission`](crate::pbr_material::StandardMaterial::diffuse_transmission)`> 0.0` +/// Add this component to make a [`Mesh3d`] using a PBR material with `StandardMaterial::diffuse_transmission > 0.0` /// receive shadows on its diffuse transmission lobe. (i.e. its “backside”) /// -/// Not enabled by default, as it requires carefully setting up [`thickness`](crate::pbr_material::StandardMaterial::thickness) +/// Not enabled by default, as it requires carefully setting up `StandardMaterial::thickness` /// (and potentially even baking a thickness texture!) to match the geometry of the mesh, in order to avoid self-shadow artifacts. /// /// **Note:** Using [`NotShadowReceiver`] overrides this component. @@ -208,12 +222,12 @@ pub struct NotShadowReceiver; #[reflect(Component, Default, Debug)] pub struct TransmittedShadowReceiver; -/// Add this component to a [`Camera3d`](bevy_core_pipeline::core_3d::Camera3d) +/// Add this component to a [`Camera3d`](bevy_camera::Camera3d) /// to control how to anti-alias shadow edges. /// /// The different modes use different approaches to /// [Percentage Closer Filtering](https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-11-shadow-map-antialiasing). -#[derive(Debug, Component, ExtractComponent, Reflect, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Component, Reflect, Clone, Copy, PartialEq, Eq, Default)] #[reflect(Component, Default, Debug, PartialEq, Clone)] pub enum ShadowFilteringMethod { /// Hardware 2x2. diff --git a/crates/bevy_pbr/src/light/point_light.rs b/crates/bevy_light/src/point_light.rs similarity index 99% rename from crates/bevy_pbr/src/light/point_light.rs rename to crates/bevy_light/src/point_light.rs index 84c024b7a2..f37a386200 100644 --- a/crates/bevy_pbr/src/light/point_light.rs +++ b/crates/bevy_light/src/point_light.rs @@ -166,7 +166,7 @@ pub struct PointLightTexture { /// /// ``` /// # use bevy_app::prelude::*; -/// # use bevy_pbr::PointLightShadowMap; +/// # use bevy_light::PointLightShadowMap; /// App::new() /// .insert_resource(PointLightShadowMap { size: 2048 }); /// ``` diff --git a/crates/bevy_light/src/probe.rs b/crates/bevy_light/src/probe.rs new file mode 100644 index 0000000000..7cd7e2f634 --- /dev/null +++ b/crates/bevy_light/src/probe.rs @@ -0,0 +1,109 @@ +use bevy_asset::Handle; +use bevy_camera::visibility::Visibility; +use bevy_ecs::prelude::*; +use bevy_image::Image; +use bevy_math::Quat; +use bevy_reflect::prelude::*; +use bevy_transform::components::Transform; + +/// A marker component for a light probe, which is a cuboid region that provides +/// global illumination to all fragments inside it. +/// +/// Note that a light probe will have no effect unless the entity contains some +/// kind of illumination, which can either be an [`EnvironmentMapLight`] or an +/// `IrradianceVolume`. +/// +/// The light probe range is conceptually a unit cube (1×1×1) centered on the +/// origin. The [`Transform`] applied to this entity can scale, rotate, or translate +/// that cube so that it contains all fragments that should take this light probe into account. +/// +/// When multiple sources of indirect illumination can be applied to a fragment, +/// the highest-quality one is chosen. Diffuse and specular illumination are +/// considered separately, so, for example, Bevy may decide to sample the +/// diffuse illumination from an irradiance volume and the specular illumination +/// from a reflection probe. From highest priority to lowest priority, the +/// ranking is as follows: +/// +/// | Rank | Diffuse | Specular | +/// | ---- | -------------------- | -------------------- | +/// | 1 | Lightmap | Lightmap | +/// | 2 | Irradiance volume | Reflection probe | +/// | 3 | Reflection probe | View environment map | +/// | 4 | View environment map | | +/// +/// Note that ambient light is always added to the diffuse component and does +/// not participate in the ranking. That is, ambient light is applied in +/// addition to, not instead of, the light sources above. +/// +/// A terminology note: Unfortunately, there is little agreement across game and +/// graphics engines as to what to call the various techniques that Bevy groups +/// under the term *light probe*. In Bevy, a *light probe* is the generic term +/// that encompasses both *reflection probes* and *irradiance volumes*. In +/// object-oriented terms, *light probe* is the superclass, and *reflection +/// probe* and *irradiance volume* are subclasses. In other engines, you may see +/// the term *light probe* refer to an irradiance volume with a single voxel, or +/// perhaps some other technique, while in Bevy *light probe* refers not to a +/// specific technique but rather to a class of techniques. Developers familiar +/// with other engines should be aware of this terminology difference. +#[derive(Component, Debug, Clone, Copy, Default, Reflect)] +#[reflect(Component, Default, Debug, Clone)] +#[require(Transform, Visibility)] +pub struct LightProbe; + +impl LightProbe { + /// Creates a new light probe component. + #[inline] + pub fn new() -> Self { + Self + } +} + +/// A pair of cubemap textures that represent the surroundings of a specific +/// area in space. +/// +/// See `bevy_pbr::environment_map` for detailed information. +#[derive(Clone, Component, Reflect)] +#[reflect(Component, Default, Clone)] +pub struct EnvironmentMapLight { + /// The blurry image that represents diffuse radiance surrounding a region. + pub diffuse_map: Handle, + + /// The typically-sharper, mipmapped image that represents specular radiance + /// surrounding a region. + pub specular_map: Handle, + + /// Scale factor applied to the diffuse and specular light generated by this component. + /// + /// After applying this multiplier, the resulting values should + /// be in units of [cd/m^2](https://en.wikipedia.org/wiki/Candela_per_square_metre). + /// + /// See also . + pub intensity: f32, + + /// World space rotation applied to the environment light cubemaps. + /// This is useful for users who require a different axis, such as the Z-axis, to serve + /// as the vertical axis. + pub rotation: Quat, + + /// Whether the light from this environment map contributes diffuse lighting + /// to meshes with lightmaps. + /// + /// Set this to false if your lightmap baking tool bakes the diffuse light + /// from this environment light into the lightmaps in order to avoid + /// counting the radiance from this environment map twice. + /// + /// By default, this is set to true. + pub affects_lightmapped_mesh_diffuse: bool, +} + +impl Default for EnvironmentMapLight { + fn default() -> Self { + EnvironmentMapLight { + diffuse_map: Handle::default(), + specular_map: Handle::default(), + intensity: 0.0, + rotation: Quat::IDENTITY, + affects_lightmapped_mesh_diffuse: true, + } + } +} diff --git a/crates/bevy_pbr/src/light/spot_light.rs b/crates/bevy_light/src/spot_light.rs similarity index 99% rename from crates/bevy_pbr/src/light/spot_light.rs rename to crates/bevy_light/src/spot_light.rs index c75a3124d3..6bb8bc0d47 100644 --- a/crates/bevy_pbr/src/light/spot_light.rs +++ b/crates/bevy_light/src/spot_light.rs @@ -1,14 +1,13 @@ use bevy_asset::Handle; use bevy_camera::{ primitives::Frustum, - visibility::{self, Visibility, VisibilityClass}, + visibility::{self, Visibility, VisibilityClass, VisibleMeshEntities}, }; use bevy_color::Color; use bevy_ecs::prelude::*; use bevy_image::Image; use bevy_math::{Mat4, Vec4}; use bevy_reflect::prelude::*; -use bevy_render::view::VisibleMeshEntities; use bevy_transform::components::{GlobalTransform, Transform}; use crate::cluster::{ClusterVisibilityClass, GlobalVisibleClusterableObjects}; diff --git a/crates/bevy_light/src/volumetric.rs b/crates/bevy_light/src/volumetric.rs new file mode 100644 index 0000000000..347731985d --- /dev/null +++ b/crates/bevy_light/src/volumetric.rs @@ -0,0 +1,157 @@ +use bevy_asset::Handle; +use bevy_camera::visibility::Visibility; +use bevy_color::Color; +use bevy_ecs::prelude::*; +use bevy_image::Image; +use bevy_math::Vec3; +use bevy_reflect::prelude::*; +use bevy_transform::components::Transform; + +/// Add this component to a [`DirectionalLight`](crate::DirectionalLight) with a shadow map +/// (`shadows_enabled: true`) to make volumetric fog interact with it. +/// +/// This allows the light to generate light shafts/god rays. +#[derive(Clone, Copy, Component, Default, Debug, Reflect)] +#[reflect(Component, Default, Debug, Clone)] +pub struct VolumetricLight; + +/// When placed on a [`bevy_camera::Camera3d`], enables +/// volumetric fog and volumetric lighting, also known as light shafts or god +/// rays. +#[derive(Clone, Copy, Component, Debug, Reflect)] +#[reflect(Component, Default, Debug, Clone)] +pub struct VolumetricFog { + /// Color of the ambient light. + /// + /// This is separate from Bevy's [`AmbientLight`](crate::AmbientLight) because an + /// [`EnvironmentMapLight`](crate::EnvironmentMapLight) is + /// still considered an ambient light for the purposes of volumetric fog. If you're using a + /// [`EnvironmentMapLight`](crate::EnvironmentMapLight), for best results, + /// this should be a good approximation of the average color of the environment map. + /// + /// Defaults to white. + pub ambient_color: Color, + + /// The brightness of the ambient light. + /// + /// If there's no [`EnvironmentMapLight`](crate::EnvironmentMapLight), + /// set this to 0. + /// + /// Defaults to 0.1. + pub ambient_intensity: f32, + + /// The maximum distance to offset the ray origin randomly by, in meters. + /// + /// This is intended for use with temporal antialiasing. It helps fog look + /// less blocky by varying the start position of the ray, using interleaved + /// gradient noise. + pub jitter: f32, + + /// The number of raymarching steps to perform. + /// + /// Higher values produce higher-quality results with less banding, but + /// reduce performance. + /// + /// The default value is 64. + pub step_count: u32, +} + +impl Default for VolumetricFog { + fn default() -> Self { + Self { + step_count: 64, + // Matches `AmbientLight` defaults. + ambient_color: Color::WHITE, + ambient_intensity: 0.1, + jitter: 0.0, + } + } +} + +#[derive(Clone, Component, Debug, Reflect)] +#[reflect(Component, Default, Debug, Clone)] +#[require(Transform, Visibility)] +pub struct FogVolume { + /// The color of the fog. + /// + /// Note that the fog must be lit by a [`VolumetricLight`] or ambient light + /// in order for this color to appear. + /// + /// Defaults to white. + pub fog_color: Color, + + /// The density of fog, which measures how dark the fog is. + /// + /// The default value is 0.1. + pub density_factor: f32, + + /// Optional 3D voxel density texture for the fog. + pub density_texture: Option>, + + /// Configurable offset of the density texture in UVW coordinates. + /// + /// This can be used to scroll a repeating density texture in a direction over time + /// to create effects like fog moving in the wind. Make sure to configure the texture + /// to use `ImageAddressMode::Repeat` if this is your intention. + /// + /// Has no effect when no density texture is present. + /// + /// The default value is (0, 0, 0). + pub density_texture_offset: Vec3, + + /// The absorption coefficient, which measures what fraction of light is + /// absorbed by the fog at each step. + /// + /// Increasing this value makes the fog darker. + /// + /// The default value is 0.3. + pub absorption: f32, + + /// The scattering coefficient, which measures the fraction of light that's + /// scattered toward, and away from, the viewer. + /// + /// The default value is 0.3. + pub scattering: f32, + + /// Measures the fraction of light that's scattered *toward* the camera, as + /// opposed to *away* from the camera. + /// + /// Increasing this value makes light shafts become more prominent when the + /// camera is facing toward their source and less prominent when the camera + /// is facing away. Essentially, a high value here means the light shafts + /// will fade into view as the camera focuses on them and fade away when the + /// camera is pointing away. + /// + /// The default value is 0.8. + pub scattering_asymmetry: f32, + + /// Applies a nonphysical color to the light. + /// + /// This can be useful for artistic purposes but is nonphysical. + /// + /// The default value is white. + pub light_tint: Color, + + /// Scales the light by a fixed fraction. + /// + /// This can be useful for artistic purposes but is nonphysical. + /// + /// The default value is 1.0, which results in no adjustment. + pub light_intensity: f32, +} + +impl Default for FogVolume { + fn default() -> Self { + Self { + absorption: 0.3, + scattering: 0.3, + density_factor: 0.1, + density_texture: None, + density_texture_offset: Vec3::ZERO, + scattering_asymmetry: 0.5, + fog_color: Color::WHITE, + light_tint: Color::WHITE, + light_intensity: 1.0, + } + } +} diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index f183e4e044..24e0a79616 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -9,12 +9,12 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -webgl = [] -webgpu = [] +webgl = ["bevy_light/webgl"] +webgpu = ["bevy_light/webgpu"] pbr_transmission_textures = [] pbr_multi_layer_material_textures = [] pbr_anisotropy_texture = [] -experimental_pbr_pcss = [] +experimental_pbr_pcss = ["bevy_light/experimental_pbr_pcss"] pbr_specular_textures = [] pbr_clustered_decals = [] pbr_light_textures = [] @@ -40,6 +40,7 @@ bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.17.0-dev" } bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" } bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" } +bevy_light = { path = "../bevy_light", version = "0.17.0-dev" } bevy_image = { path = "../bevy_image", version = "0.17.0-dev" } bevy_math = { path = "../bevy_math", version = "0.17.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" } diff --git a/crates/bevy_pbr/src/cluster/extract_and_prepare.rs b/crates/bevy_pbr/src/cluster.rs similarity index 99% rename from crates/bevy_pbr/src/cluster/extract_and_prepare.rs rename to crates/bevy_pbr/src/cluster.rs index 53187a2b02..9c47859deb 100644 --- a/crates/bevy_pbr/src/cluster/extract_and_prepare.rs +++ b/crates/bevy_pbr/src/cluster.rs @@ -2,6 +2,7 @@ use core::num::NonZero; use bevy_camera::Camera; use bevy_ecs::{entity::EntityHashMap, prelude::*}; +use bevy_light::cluster::{ClusterableObjectCounts, Clusters, GlobalClusterSettings}; use bevy_math::{uvec4, UVec3, UVec4, Vec4}; use bevy_render::{ render_resource::{ @@ -13,7 +14,6 @@ use bevy_render::{ }; use tracing::warn; -use super::{ClusterableObjectCounts, Clusters, GlobalClusterSettings}; use crate::MeshPipeline; // NOTE: this must be kept in sync with the same constants in diff --git a/crates/bevy_pbr/src/decal/clustered.rs b/crates/bevy_pbr/src/decal/clustered.rs index d4ac27a1f5..7580f1475e 100644 --- a/crates/bevy_pbr/src/decal/clustered.rs +++ b/crates/bevy_pbr/src/decal/clustered.rs @@ -27,6 +27,8 @@ use bevy_ecs::{ system::{Query, Res, ResMut}, }; use bevy_image::Image; +pub use bevy_light::cluster::ClusteredDecal; +use bevy_light::{DirectionalLightTexture, PointLightTexture, SpotLightTexture}; use bevy_math::Mat4; use bevy_platform::collections::HashMap; pub use bevy_render::primitives::CubemapLayout; @@ -47,9 +49,7 @@ use bevy_render::{ use bevy_transform::components::GlobalTransform; use bytemuck::{Pod, Zeroable}; -pub use crate::ClusteredDecal; use crate::{binding_arrays_are_usable, prepare_lights, GlobalClusterableObjectMeta}; -pub use crate::{DirectionalLightTexture, PointLightTexture, SpotLightTexture}; /// The maximum number of decals that can be present in a view. /// diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index f4718a175e..96569b2861 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -1,14 +1,11 @@ use crate::{ - graph::NodePbr, irradiance_volume::IrradianceVolume, prelude::EnvironmentMapLight, - MeshPipeline, MeshViewBindGroup, RenderViewLightProbes, ScreenSpaceAmbientOcclusion, - ScreenSpaceReflectionsUniform, ViewEnvironmentMapUniformOffset, ViewLightProbesUniformOffset, + graph::NodePbr, irradiance_volume::IrradianceVolume, MeshPipeline, MeshViewBindGroup, + RenderViewLightProbes, ScreenSpaceAmbientOcclusion, ScreenSpaceReflectionsUniform, + ViewEnvironmentMapUniformOffset, ViewLightProbesUniformOffset, ViewScreenSpaceReflectionsUniformOffset, TONEMAPPING_LUT_SAMPLER_BINDING_INDEX, TONEMAPPING_LUT_TEXTURE_BINDING_INDEX, }; -use crate::{ - DistanceFog, MeshPipelineKey, ShadowFilteringMethod, ViewFogUniformOffset, - ViewLightsUniformOffset, -}; +use crate::{DistanceFog, MeshPipelineKey, ViewFogUniformOffset, ViewLightsUniformOffset}; use bevy_app::prelude::*; use bevy_asset::{embedded_asset, load_embedded_asset, Handle}; use bevy_core_pipeline::{ @@ -21,6 +18,7 @@ use bevy_core_pipeline::{ }; use bevy_ecs::{prelude::*, query::QueryItem}; use bevy_image::BevyDefault as _; +use bevy_light::{EnvironmentMapLight, ShadowFilteringMethod}; use bevy_render::{ extract_component::{ ComponentUniforms, ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin, diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index cad7b8979c..994cb72b25 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -31,7 +31,6 @@ pub mod decal; pub mod deferred; mod extended_material; mod fog; -mod light; mod light_probe; mod lightmap; mod material; @@ -48,12 +47,19 @@ mod volumetric_fog; use bevy_color::{Color, LinearRgba}; pub use atmosphere::*; +use bevy_light::SimulationLightSystems; +pub use bevy_light::{ + light_consts, AmbientLight, CascadeShadowConfig, CascadeShadowConfigBuilder, Cascades, + ClusteredDecal, DirectionalLight, DirectionalLightShadowMap, DirectionalLightTexture, + FogVolume, LightPlugin, LightProbe, NotShadowCaster, NotShadowReceiver, PointLight, + PointLightShadowMap, PointLightTexture, ShadowFilteringMethod, SpotLight, SpotLightTexture, + TransmittedShadowReceiver, VolumetricFog, VolumetricLight, +}; pub use cluster::*; pub use components::*; pub use decal::clustered::ClusteredDecalPlugin; pub use extended_material::*; pub use fog::*; -pub use light::*; pub use light_probe::*; pub use lightmap::*; pub use material::*; @@ -65,7 +71,7 @@ pub use prepass::*; pub use render::*; pub use ssao::*; pub use ssr::*; -pub use volumetric_fog::{FogVolume, VolumetricFog, VolumetricFogPlugin, VolumetricLight}; +pub use volumetric_fog::VolumetricFogPlugin; /// The PBR prelude. /// @@ -74,14 +80,17 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ fog::{DistanceFog, FogFalloff}, - light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight}, - light_probe::{environment_map::EnvironmentMapLight, LightProbe}, material::{Material, MaterialPlugin}, mesh_material::MeshMaterial3d, parallax::ParallaxMappingMethod, pbr_material::StandardMaterial, ssao::ScreenSpaceAmbientOcclusionPlugin, }; + #[doc(hidden)] + pub use bevy_light::{ + light_consts, AmbientLight, DirectionalLight, EnvironmentMapLight, LightProbe, PointLight, + SpotLight, + }; } pub mod graph { @@ -122,7 +131,6 @@ pub mod graph { } } -pub use crate::cascade::{CascadeShadowConfig, CascadeShadowConfigBuilder, Cascades}; use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr}; use bevy_app::prelude::*; use bevy_asset::{AssetApp, AssetPath, Assets, Handle}; @@ -203,8 +211,6 @@ impl Plugin for PbrPlugin { load_shader_library!(app, "meshlet/dummy_visibility_buffer_resolve.wgsl"); app.register_asset_reflect::() - .register_type::() - .init_resource::() .register_type::() .init_resource::() .add_plugins(( diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_pbr/src/light_probe/environment_map.rs index fa55b4d94a..e6dfebd903 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -44,13 +44,10 @@ //! //! [several pre-filtered environment maps]: https://github.com/KhronosGroup/glTF-Sample-Environments -use bevy_asset::{AssetId, Handle}; -use bevy_ecs::{ - component::Component, query::QueryItem, reflect::ReflectComponent, system::lifetimeless::Read, -}; +use bevy_asset::AssetId; +use bevy_ecs::{query::QueryItem, system::lifetimeless::Read}; use bevy_image::Image; -use bevy_math::Quat; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_light::EnvironmentMapLight; use bevy_render::{ extract_instances::ExtractInstance, render_asset::RenderAssets, @@ -72,56 +69,6 @@ use crate::{ use super::{LightProbeComponent, RenderViewLightProbes}; -/// A pair of cubemap textures that represent the surroundings of a specific -/// area in space. -/// -/// See [`crate::environment_map`] for detailed information. -#[derive(Clone, Component, Reflect)] -#[reflect(Component, Default, Clone)] -pub struct EnvironmentMapLight { - /// The blurry image that represents diffuse radiance surrounding a region. - pub diffuse_map: Handle, - - /// The typically-sharper, mipmapped image that represents specular radiance - /// surrounding a region. - pub specular_map: Handle, - - /// Scale factor applied to the diffuse and specular light generated by this component. - /// - /// After applying this multiplier, the resulting values should - /// be in units of [cd/m^2](https://en.wikipedia.org/wiki/Candela_per_square_metre). - /// - /// See also . - pub intensity: f32, - - /// World space rotation applied to the environment light cubemaps. - /// This is useful for users who require a different axis, such as the Z-axis, to serve - /// as the vertical axis. - pub rotation: Quat, - - /// Whether the light from this environment map contributes diffuse lighting - /// to meshes with lightmaps. - /// - /// Set this to false if your lightmap baking tool bakes the diffuse light - /// from this environment light into the lightmaps in order to avoid - /// counting the radiance from this environment map twice. - /// - /// By default, this is set to true. - pub affects_lightmapped_mesh_diffuse: bool, -} - -impl Default for EnvironmentMapLight { - fn default() -> Self { - EnvironmentMapLight { - diffuse_map: Handle::default(), - specular_map: Handle::default(), - intensity: 0.0, - rotation: Quat::IDENTITY, - affects_lightmapped_mesh_diffuse: true, - } - } -} - /// Like [`EnvironmentMapLight`], but contains asset IDs instead of handles. /// /// This is for use in the render app. diff --git a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs index e2dea463f2..49fa9185d3 100644 --- a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs +++ b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs @@ -135,6 +135,7 @@ use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_image::Image; +use bevy_light::LightProbe; use bevy_render::{ render_asset::RenderAssets, render_resource::{ @@ -155,7 +156,7 @@ use crate::{ MAX_VIEW_LIGHT_PROBES, }; -use super::{LightProbe, LightProbeComponent}; +use super::LightProbeComponent; /// On WebGL and WebGPU, we must disable irradiance volumes, as otherwise we can /// overflow the number of texture bindings when deferred rendering is in use diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 82035be2f6..2884c86a2f 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -8,15 +8,14 @@ use bevy_ecs::{ component::Component, entity::Entity, query::With, - reflect::ReflectComponent, resource::Resource, schedule::IntoScheduleConfigs, system::{Commands, Local, Query, Res, ResMut}, }; use bevy_image::Image; +use bevy_light::{EnvironmentMapLight, LightProbe}; use bevy_math::{Affine3A, FloatOrd, Mat4, Vec3A, Vec4}; use bevy_platform::collections::HashMap; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ extract_instances::ExtractInstancesPlugin, load_shader_library, @@ -27,7 +26,7 @@ use bevy_render::{ settings::WgpuFeatures, sync_world::RenderEntity, texture::{FallbackImage, GpuImage}, - view::{ExtractedView, Visibility}, + view::ExtractedView, Extract, ExtractSchedule, Render, RenderApp, RenderSystems, }; use bevy_transform::{components::Transform, prelude::GlobalTransform}; @@ -35,7 +34,7 @@ use tracing::error; use core::{hash::Hash, ops::Deref}; -use crate::light_probe::environment_map::{EnvironmentMapIds, EnvironmentMapLight}; +use crate::light_probe::environment_map::EnvironmentMapIds; use self::irradiance_volume::IrradianceVolume; @@ -59,50 +58,6 @@ const STANDARD_MATERIAL_FRAGMENT_SHADER_MIN_TEXTURE_BINDINGS: usize = 16; /// cubemaps applied to all objects that a view renders. pub struct LightProbePlugin; -/// A marker component for a light probe, which is a cuboid region that provides -/// global illumination to all fragments inside it. -/// -/// Note that a light probe will have no effect unless the entity contains some -/// kind of illumination, which can either be an [`EnvironmentMapLight`] or an -/// [`IrradianceVolume`]. -/// -/// The light probe range is conceptually a unit cube (1×1×1) centered on the -/// origin. The [`Transform`] applied to this entity can scale, rotate, or translate -/// that cube so that it contains all fragments that should take this light probe into account. -/// -/// When multiple sources of indirect illumination can be applied to a fragment, -/// the highest-quality one is chosen. Diffuse and specular illumination are -/// considered separately, so, for example, Bevy may decide to sample the -/// diffuse illumination from an irradiance volume and the specular illumination -/// from a reflection probe. From highest priority to lowest priority, the -/// ranking is as follows: -/// -/// | Rank | Diffuse | Specular | -/// | ---- | -------------------- | -------------------- | -/// | 1 | Lightmap | Lightmap | -/// | 2 | Irradiance volume | Reflection probe | -/// | 3 | Reflection probe | View environment map | -/// | 4 | View environment map | | -/// -/// Note that ambient light is always added to the diffuse component and does -/// not participate in the ranking. That is, ambient light is applied in -/// addition to, not instead of, the light sources above. -/// -/// A terminology note: Unfortunately, there is little agreement across game and -/// graphics engines as to what to call the various techniques that Bevy groups -/// under the term *light probe*. In Bevy, a *light probe* is the generic term -/// that encompasses both *reflection probes* and *irradiance volumes*. In -/// object-oriented terms, *light probe* is the superclass, and *reflection -/// probe* and *irradiance volume* are subclasses. In other engines, you may see -/// the term *light probe* refer to an irradiance volume with a single voxel, or -/// perhaps some other technique, while in Bevy *light probe* refers not to a -/// specific technique but rather to a class of techniques. Developers familiar -/// with other engines should be aware of this terminology difference. -#[derive(Component, Debug, Clone, Copy, Default, Reflect)] -#[reflect(Component, Default, Debug, Clone)] -#[require(Transform, Visibility)] -pub struct LightProbe; - /// A GPU type that stores information about a light probe. #[derive(Clone, Copy, ShaderType, Default)] struct RenderLightProbe { @@ -302,14 +257,6 @@ pub trait LightProbeComponent: Send + Sync + Component + Sized { ) -> RenderViewLightProbes; } -impl LightProbe { - /// Creates a new light probe component. - #[inline] - pub fn new() -> Self { - Self - } -} - /// The uniform struct extracted from [`EnvironmentMapLight`]. /// Will be available for use in the Environment Map shader. #[derive(Component, ShaderType, Clone)] @@ -341,9 +288,7 @@ impl Plugin for LightProbePlugin { load_shader_library!(app, "environment_map.wgsl"); load_shader_library!(app, "irradiance_volume.wgsl"); - app.register_type::() - .register_type::() - .register_type::() + app.register_type::() .add_plugins(ExtractInstancesPlugin::::new()); } diff --git a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs index 95c8859520..1ec316dcd8 100644 --- a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs +++ b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs @@ -2,13 +2,14 @@ use super::{ instance_manager::InstanceManager, pipelines::MeshletPipelines, resource_manager::ResourceManager, }; -use crate::{environment_map::EnvironmentMapLight, irradiance_volume::IrradianceVolume, *}; +use crate::{irradiance_volume::IrradianceVolume, *}; use bevy_core_pipeline::{ core_3d::Camera3d, prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, tonemapping::{DebandDither, Tonemapping}, }; use bevy_derive::{Deref, DerefMut}; +use bevy_light::EnvironmentMapLight; use bevy_platform::collections::{HashMap, HashSet}; use bevy_render::erased_render_asset::ErasedRenderAssets; use bevy_render::{ diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 883147acc3..74dc0ff15d 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,6 +1,3 @@ -use self::assign::ClusterableObjectType; -use crate::assign::calculate_cluster_factors; -use crate::cascade::{Cascade, CascadeShadowConfig, Cascades}; use crate::*; use bevy_asset::UntypedAssetId; pub use bevy_camera::primitives::{face_index_to_name, CubeMapFace, CUBE_MAP_FACES}; @@ -14,6 +11,13 @@ use bevy_ecs::{ prelude::*, system::lifetimeless::Read, }; +use bevy_light::cascade::Cascade; +use bevy_light::cluster::assign::{calculate_cluster_factors, ClusterableObjectType}; +use bevy_light::cluster::GlobalVisibleClusterableObjects; +use bevy_light::{ + spot_light_clip_from_view, spot_light_world_from_view, DirectionalLightShadowMap, + NotShadowCaster, PointLightShadowMap, +}; use bevy_math::{ops, Mat4, UVec4, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_platform::collections::{HashMap, HashSet}; use bevy_platform::hash::FixedHasher; @@ -798,7 +802,7 @@ pub fn prepare_lights( // - then by entity as a stable key to ensure that a consistent set of lights are chosen if the light count limit is exceeded. point_lights.sort_by_cached_key(|(entity, _, light, _)| { ( - ClusterableObjectType::from_point_or_spot_light(light).ordering(), + point_or_spot_light_to_clusterable(light).ordering(), *entity, ) }); @@ -2265,3 +2269,18 @@ impl ShadowPassNode { Ok(()) } } + +/// Creates the [`ClusterableObjectType`] data for a point or spot light. +fn point_or_spot_light_to_clusterable(point_light: &ExtractedPointLight) -> ClusterableObjectType { + match point_light.spot_light_angles { + Some((_, outer_angle)) => ClusterableObjectType::SpotLight { + outer_angle, + shadows_enabled: point_light.shadows_enabled, + volumetric: point_light.volumetric, + }, + None => ClusterableObjectType::PointLight { + shadows_enabled: point_light.shadows_enabled, + volumetric: point_light.volumetric, + }, + } +} diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index dff8edb32b..2e9562c5f8 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -15,6 +15,9 @@ use bevy_ecs::{ system::{lifetimeless::*, SystemParamItem, SystemState}, }; use bevy_image::{BevyDefault, ImageSampler, TextureFormatPixelInfo}; +use bevy_light::{ + EnvironmentMapLight, NotShadowCaster, NotShadowReceiver, TransmittedShadowReceiver, +}; use bevy_math::{Affine3, Rect, UVec2, Vec3, Vec4}; use bevy_platform::collections::{hash_map::Entry, HashMap}; use bevy_render::{ @@ -52,7 +55,6 @@ use material_bind_groups::MaterialBindingId; use tracing::{error, warn}; use self::irradiance_volume::IRRADIANCE_VOLUMES_ARE_USABLE; -use crate::environment_map::EnvironmentMapLight; use crate::irradiance_volume::IrradianceVolume; use crate::{ render::{ diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 03165f1bc5..0f40327dc7 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -17,6 +17,7 @@ use bevy_ecs::{ world::{FromWorld, World}, }; use bevy_image::BevyDefault as _; +use bevy_light::EnvironmentMapLight; use bevy_math::Vec4; use bevy_render::{ globals::{GlobalsBuffer, GlobalsUniform}, @@ -30,7 +31,6 @@ use bevy_render::{ }, }; use core::{array, num::NonZero}; -use environment_map::EnvironmentMapLight; use crate::{ decal::{ diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_pbr/src/volumetric_fog/mod.rs index c9f1f230c6..a4099aeb62 100644 --- a/crates/bevy_pbr/src/volumetric_fog/mod.rs +++ b/crates/bevy_pbr/src/volumetric_fog/mod.rs @@ -6,14 +6,14 @@ //! for light beams from directional lights to shine through, creating what is //! known as *light shafts* or *god rays*. //! -//! To add volumetric fog to a scene, add [`VolumetricFog`] to the -//! camera, and add [`VolumetricLight`] to directional lights that you wish to -//! be volumetric. [`VolumetricFog`] feature numerous settings that +//! To add volumetric fog to a scene, add [`crate::VolumetricFog`] to the +//! camera, and add [`crate::VolumetricLight`] to directional lights that you wish to +//! be volumetric. [`crate::VolumetricFog`] feature numerous settings that //! allow you to define the accuracy of the simulation, as well as the look of //! the fog. Currently, only interaction with directional lights that have //! shadow maps is supported. Note that the overhead of the effect scales //! directly with the number of directional lights in use, so apply -//! [`VolumetricLight`] sparingly for the best results. +//! [`crate::VolumetricLight`] sparingly for the best results. //! //! The overall algorithm, which is implemented as a postprocessing effect, is a //! combination of the techniques described in [Scratchapixel] and [this blog @@ -30,30 +30,24 @@ //! [Henyey-Greenstein phase function]: https://www.pbr-book.org/4ed/Volume_Scattering/Phase_Functions#TheHenyeyndashGreensteinPhaseFunction use bevy_app::{App, Plugin}; -use bevy_asset::{embedded_asset, Assets, Handle}; -use bevy_color::Color; +use bevy_asset::{embedded_asset, Assets}; use bevy_core_pipeline::core_3d::{ graph::{Core3d, Node3d}, prepare_core_3d_depth_textures, }; -use bevy_ecs::{ - component::Component, reflect::ReflectComponent, schedule::IntoScheduleConfigs as _, -}; -use bevy_image::Image; +use bevy_ecs::schedule::IntoScheduleConfigs as _; +use bevy_light::FogVolume; use bevy_math::{ primitives::{Cuboid, Plane3d}, Vec2, Vec3, }; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ mesh::{Mesh, Meshable}, render_graph::{RenderGraphExt, ViewNodeRunner}, render_resource::SpecializedRenderPipelines, sync_component::SyncComponentPlugin, - view::Visibility, ExtractSchedule, Render, RenderApp, RenderSystems, }; -use bevy_transform::components::Transform; use render::{ VolumetricFogNode, VolumetricFogPipeline, VolumetricFogUniformBuffer, CUBE_MESH, PLANE_MESH, }; @@ -65,127 +59,6 @@ pub mod render; /// A plugin that implements volumetric fog. pub struct VolumetricFogPlugin; -/// Add this component to a [`DirectionalLight`](crate::DirectionalLight) with a shadow map -/// (`shadows_enabled: true`) to make volumetric fog interact with it. -/// -/// This allows the light to generate light shafts/god rays. -#[derive(Clone, Copy, Component, Default, Debug, Reflect)] -#[reflect(Component, Default, Debug, Clone)] -pub struct VolumetricLight; - -/// When placed on a [`bevy_core_pipeline::core_3d::Camera3d`], enables -/// volumetric fog and volumetric lighting, also known as light shafts or god -/// rays. -#[derive(Clone, Copy, Component, Debug, Reflect)] -#[reflect(Component, Default, Debug, Clone)] -pub struct VolumetricFog { - /// Color of the ambient light. - /// - /// This is separate from Bevy's [`AmbientLight`](crate::light::AmbientLight) because an - /// [`EnvironmentMapLight`](crate::environment_map::EnvironmentMapLight) is - /// still considered an ambient light for the purposes of volumetric fog. If you're using a - /// [`EnvironmentMapLight`](crate::environment_map::EnvironmentMapLight), for best results, - /// this should be a good approximation of the average color of the environment map. - /// - /// Defaults to white. - pub ambient_color: Color, - - /// The brightness of the ambient light. - /// - /// If there's no [`EnvironmentMapLight`](crate::environment_map::EnvironmentMapLight), - /// set this to 0. - /// - /// Defaults to 0.1. - pub ambient_intensity: f32, - - /// The maximum distance to offset the ray origin randomly by, in meters. - /// - /// This is intended for use with temporal antialiasing. It helps fog look - /// less blocky by varying the start position of the ray, using interleaved - /// gradient noise. - pub jitter: f32, - - /// The number of raymarching steps to perform. - /// - /// Higher values produce higher-quality results with less banding, but - /// reduce performance. - /// - /// The default value is 64. - pub step_count: u32, -} - -#[derive(Clone, Component, Debug, Reflect)] -#[reflect(Component, Default, Debug, Clone)] -#[require(Transform, Visibility)] -pub struct FogVolume { - /// The color of the fog. - /// - /// Note that the fog must be lit by a [`VolumetricLight`] or ambient light - /// in order for this color to appear. - /// - /// Defaults to white. - pub fog_color: Color, - - /// The density of fog, which measures how dark the fog is. - /// - /// The default value is 0.1. - pub density_factor: f32, - - /// Optional 3D voxel density texture for the fog. - pub density_texture: Option>, - - /// Configurable offset of the density texture in UVW coordinates. - /// - /// This can be used to scroll a repeating density texture in a direction over time - /// to create effects like fog moving in the wind. Make sure to configure the texture - /// to use `ImageAddressMode::Repeat` if this is your intention. - /// - /// Has no effect when no density texture is present. - /// - /// The default value is (0, 0, 0). - pub density_texture_offset: Vec3, - - /// The absorption coefficient, which measures what fraction of light is - /// absorbed by the fog at each step. - /// - /// Increasing this value makes the fog darker. - /// - /// The default value is 0.3. - pub absorption: f32, - - /// The scattering coefficient, which measures the fraction of light that's - /// scattered toward, and away from, the viewer. - /// - /// The default value is 0.3. - pub scattering: f32, - - /// Measures the fraction of light that's scattered *toward* the camera, as - /// opposed to *away* from the camera. - /// - /// Increasing this value makes light shafts become more prominent when the - /// camera is facing toward their source and less prominent when the camera - /// is facing away. Essentially, a high value here means the light shafts - /// will fade into view as the camera focuses on them and fade away when the - /// camera is pointing away. - /// - /// The default value is 0.8. - pub scattering_asymmetry: f32, - - /// Applies a nonphysical color to the light. - /// - /// This can be useful for artistic purposes but is nonphysical. - /// - /// The default value is white. - pub light_tint: Color, - - /// Scales the light by a fixed fraction. - /// - /// This can be useful for artistic purposes but is nonphysical. - /// - /// The default value is 1.0, which results in no adjustment. - pub light_intensity: f32, -} - impl Plugin for VolumetricFogPlugin { fn build(&self, app: &mut App) { embedded_asset!(app, "volumetric_fog.wgsl"); @@ -194,9 +67,6 @@ impl Plugin for VolumetricFogPlugin { meshes.insert(&PLANE_MESH, Plane3d::new(Vec3::Z, Vec2::ONE).mesh().into()); meshes.insert(&CUBE_MESH, Cuboid::new(1.0, 1.0, 1.0).mesh().into()); - app.register_type::() - .register_type::(); - app.add_plugins(SyncComponentPlugin::::default()); let Some(render_app) = app.get_sub_app_mut(RenderApp) else { @@ -238,31 +108,3 @@ impl Plugin for VolumetricFogPlugin { ); } } - -impl Default for VolumetricFog { - fn default() -> Self { - Self { - step_count: 64, - // Matches `AmbientLight` defaults. - ambient_color: Color::WHITE, - ambient_intensity: 0.1, - jitter: 0.0, - } - } -} - -impl Default for FogVolume { - fn default() -> Self { - Self { - absorption: 0.3, - scattering: 0.3, - density_factor: 0.1, - density_texture: None, - density_texture_offset: Vec3::ZERO, - scattering_asymmetry: 0.5, - fog_color: Color::WHITE, - light_tint: Color::WHITE, - light_intensity: 1.0, - } - } -} diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 27463b9272..4049656b4b 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -77,6 +77,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev" } bevy_image = { path = "../bevy_image", version = "0.17.0-dev" } bevy_mesh = { path = "../bevy_mesh", version = "0.17.0-dev" } bevy_camera = { path = "../bevy_camera", version = "0.17.0-dev" } +bevy_light = { path = "../bevy_light", version = "0.17.0-dev" } bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [ "std", "serialize", diff --git a/crates/bevy_render/src/extract_impls.rs b/crates/bevy_render/src/extract_impls.rs new file mode 100644 index 0000000000..87b854363a --- /dev/null +++ b/crates/bevy_render/src/extract_impls.rs @@ -0,0 +1,41 @@ +//! This module exists because of the orphan rule + +use bevy_ecs::query::QueryItem; +use bevy_light::{cluster::ClusteredDecal, AmbientLight, ShadowFilteringMethod}; + +use crate::{extract_component::ExtractComponent, extract_resource::ExtractResource}; + +impl ExtractComponent for ClusteredDecal { + type QueryData = &'static Self; + type QueryFilter = (); + type Out = Self; + + fn extract_component(item: QueryItem) -> Option { + Some(item.clone()) + } +} +impl ExtractResource for AmbientLight { + type Source = Self; + + fn extract_resource(source: &Self::Source) -> Self { + source.clone() + } +} +impl ExtractComponent for AmbientLight { + type QueryData = &'static Self; + type QueryFilter = (); + type Out = Self; + + fn extract_component(item: QueryItem) -> Option { + Some(item.clone()) + } +} +impl ExtractComponent for ShadowFilteringMethod { + type QueryData = &'static Self; + type QueryFilter = (); + type Out = Self; + + fn extract_component(item: QueryItem) -> Option { + Some(*item) + } +} diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index a7907178ba..471a672540 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -50,6 +50,7 @@ pub mod sync_world; pub mod texture; pub mod view; pub use bevy_camera::primitives; +mod extract_impls; /// The render prelude. /// diff --git a/examples/3d/light_textures.rs b/examples/3d/light_textures.rs index 94ddd159f2..babaa9b8a8 100644 --- a/examples/3d/light_textures.rs +++ b/examples/3d/light_textures.rs @@ -6,13 +6,7 @@ use std::fmt::{self, Formatter}; use bevy::{ color::palettes::css::{SILVER, YELLOW}, input::mouse::AccumulatedMouseMotion, - pbr::{ - decal::{ - self, - clustered::{DirectionalLightTexture, PointLightTexture, SpotLightTexture}, - }, - NotShadowCaster, - }, + pbr::{decal, DirectionalLightTexture, NotShadowCaster, PointLightTexture, SpotLightTexture}, prelude::*, render::renderer::{RenderAdapter, RenderDevice}, window::SystemCursorIcon, diff --git a/tools/example-showcase/reduce-light-cluster-config.patch b/tools/example-showcase/reduce-light-cluster-config.patch index 1f3a80f0e5..c0bd2ae910 100644 --- a/tools/example-showcase/reduce-light-cluster-config.patch +++ b/tools/example-showcase/reduce-light-cluster-config.patch @@ -1,8 +1,8 @@ diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index a8c218b44..13cc9f9c6 100644 ---- a/crates/bevy_pbr/src/cluster/mod.rs -+++ b/crates/bevy_pbr/src/cluster/mod.rs -@@ -239,8 +239,8 @@ impl Default for ClusterConfig { +--- a/crates/bevy_light/src/cluster/mod.rs ++++ b/crates/bevy_light/src/cluster/mod.rs +@@ -185,8 +185,8 @@ impl Default for ClusterConfig { // 24 depth slices, square clusters with at most 4096 total clusters // use max light distance as clusters max `Z`-depth, first slice extends to 5.0 Self::FixedZ {