Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0778d9c
Revert "Revert "Replace Ambient Lights with Environment Map Lights (#…
SparkyPotato Mar 9, 2025
8274ccf
replace default AmbientLight with default EnvironmentMapLight
SparkyPotato Mar 10, 2025
492016b
clippy
SparkyPotato Mar 10, 2025
247c829
rustdoc
SparkyPotato Mar 10, 2025
f43b4a8
merge master
SparkyPotato Jul 28, 2025
f52ac2d
get rid of unneeded extracts
SparkyPotato Jul 28, 2025
3e44275
merge main but up to date this time
SparkyPotato Jul 28, 2025
c70513b
fix ci
SparkyPotato Jul 28, 2025
6379011
fix invalid skinned mesh test
SparkyPotato Jul 28, 2025
1ea7cf5
clippy
SparkyPotato Jul 28, 2025
1c4a8c9
fix doc
SparkyPotato Jul 28, 2025
362be00
add migration guide
SparkyPotato Jul 28, 2025
c87a15c
apply my feedback
atlv24 Aug 2, 2025
fb3a807
Merge pull request #2 from atlv24/ad/ambient-feedback
SparkyPotato Aug 2, 2025
c2bb959
Merge branch 'main' into revert-18167-revert-ambient-light-change
SparkyPotato Aug 2, 2025
435af5d
fix
atlv24 Aug 2, 2025
0f2d7b6
Merge pull request #3 from atlv24/ad/fix-default
SparkyPotato Aug 2, 2025
7256c26
fix wgpu
atlv24 Aug 2, 2025
77f7333
Merge pull request #4 from atlv24/ad/wgpufix
SparkyPotato Aug 2, 2025
4c7c2f0
fmt
atlv24 Aug 2, 2025
eab52ce
Merge pull request #5 from atlv24/ad/fmt
SparkyPotato Aug 2, 2025
e58a1b7
update default environment light
SparkyPotato Aug 5, 2025
d3fb19b
fix lighting example
SparkyPotato Aug 5, 2025
47529ae
Merge branch 'main' into revert-18167-revert-ambient-light-change
SparkyPotato Aug 5, 2025
83fe161
fix examples
atlv24 Aug 5, 2025
613f3bf
Merge pull request #6 from atlv24/ad/fixes
SparkyPotato Aug 5, 2025
e4798f3
fix again :(
atlv24 Aug 5, 2025
80b718b
Merge pull request #7 from atlv24/ad/fix-again
SparkyPotato Aug 5, 2025
40ea776
merge main
SparkyPotato Aug 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_light/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ bevy_color = { path = "../bevy_color", version = "0.17.0-dev", features = [

# other
tracing = { version = "0.1", default-features = false }
wgpu-types = { version = "26", default-features = false }

[features]
default = []
Expand Down
7 changes: 6 additions & 1 deletion crates/bevy_light/src/ambient_light.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#![deprecated(
since = "0.17.0",
note = "Use `EnvironmentMapLight::solid_color` instead"
)]

use bevy_camera::Camera;
use bevy_color::Color;
use bevy_ecs::prelude::*;
Expand Down Expand Up @@ -48,7 +53,7 @@ impl Default for AmbientLight {
fn default() -> Self {
Self {
color: Color::WHITE,
brightness: 80.0,
brightness: 50.0,
affects_lightmapped_meshes: true,
}
}
Expand Down
112 changes: 107 additions & 5 deletions crates/bevy_light/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]

use bevy_app::{App, Plugin, PostUpdate};
use bevy_asset::Assets;
use bevy_camera::{
primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, Sphere},
visibility::{
CascadesVisibleEntities, CubemapVisibleEntities, InheritedVisibility, NoFrustumCulling,
PreviousVisibleEntities, RenderLayers, ViewVisibility, VisibilityRange, VisibilitySystems,
VisibleEntityRanges, VisibleMeshEntities,
},
CameraUpdateSystems,
Camera3d, CameraUpdateSystems,
};
use bevy_color::Color;
use bevy_ecs::{entity::EntityHashSet, prelude::*};
use bevy_image::Image;
use bevy_math::Vec3A;
use bevy_mesh::Mesh3d;
use bevy_reflect::prelude::*;
Expand All @@ -25,6 +28,10 @@ use cluster::{
GlobalVisibleClusterableObjects, VisibleClusterableObjects,
};
mod ambient_light;
#[expect(
deprecated,
reason = "AmbientLight has been replaced by EnvironmentMapLight"
)]
pub use ambient_light::AmbientLight;
mod probe;
pub use probe::{EnvironmentMapLight, GeneratedEnvironmentMapLight, IrradianceVolume, LightProbe};
Expand All @@ -48,7 +55,8 @@ pub use directional_light::{
DirectionalLightTexture,
};

use crate::directional_light::validate_shadow_map_size;
use directional_light::validate_shadow_map_size;
use probe::DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE;

/// Constants for operating with the light units: lumens, and lux.
pub mod light_consts {
Expand Down Expand Up @@ -113,10 +121,25 @@ pub mod light_consts {
}
}

pub struct LightPlugin;
pub struct LightPlugin {
/// Controls if the default environment map light is added to every [`Camera3d`].
pub default_environment_map_light: bool,
}

impl Default for LightPlugin {
fn default() -> Self {
Self {
default_environment_map_light: true,
}
}
}

impl Plugin for LightPlugin {
fn build(&self, app: &mut App) {
#[expect(
deprecated,
reason = "AmbientLight has been replaced by EnvironmentMapLight"
)]
app.register_type::<AmbientLight>()
.register_type::<CascadeShadowConfig>()
.register_type::<Cascades>()
Expand All @@ -135,7 +158,6 @@ impl Plugin for LightPlugin {
.register_type::<ShadowFilteringMethod>()
.register_type::<ClusterConfig>()
.init_resource::<GlobalVisibleClusterableObjects>()
.init_resource::<AmbientLight>()
.init_resource::<DirectionalLightShadowMap>()
.init_resource::<PointLightShadowMap>()
.configure_sets(
Expand All @@ -151,6 +173,9 @@ impl Plugin for LightPlugin {
.add_systems(
PostUpdate,
(
map_ambient_lights
.in_set(SimulationLightSystems::MapAmbientLights)
.after(CameraUpdateSystems),
validate_shadow_map_size.before(build_directional_light_cascades),
add_clusters
.in_set(SimulationLightSystems::AddClusters)
Expand Down Expand Up @@ -200,6 +225,25 @@ impl Plugin for LightPlugin {
.after(clear_directional_light_cascades),
),
);

if self.default_environment_map_light {
app.world_mut()
.register_required_components_with::<Camera3d, EnvironmentMapLight>(|| {
EnvironmentMapLight {
intensity: 50.0,
..Default::default()
}
});
}

app.world_mut().resource_mut::<Assets<Image>>().insert(
&DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the default environment light be pure white like this? I think a better default would be a sky-like gradient, or maybe even the atmosphere env light. probably out of scope for this PR though.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for this PR should keep it white to keep it similar to the current default of ambient light, but I agree that in the future we should consider a nicer default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree, but thats for a different PR

EnvironmentMapLight::hemispherical_gradient_cubemap(
Color::WHITE,
Color::WHITE,
Color::WHITE,
),
);
}
}

Expand Down Expand Up @@ -230,7 +274,7 @@ pub struct NotShadowReceiver;
#[reflect(Component, Default, Debug)]
pub struct TransmittedShadowReceiver;

/// Add this component to a [`Camera3d`](bevy_camera::Camera3d)
/// Add this component to a [`Camera3d`]
/// to control how to anti-alias shadow edges.
///
/// The different modes use different approaches to
Expand Down Expand Up @@ -269,6 +313,7 @@ pub enum ShadowFilteringMethod {
/// System sets used to run light-related systems.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub enum SimulationLightSystems {
MapAmbientLights,
AddClusters,
AssignLightsToClusters,
/// System order ambiguities between systems in this set are ignored:
Expand All @@ -282,6 +327,63 @@ pub enum SimulationLightSystems {
CheckLightVisibility,
}

#[derive(Component)]
pub struct EnvironmentMapLightFromAmbientLight;

#[expect(
deprecated,
reason = "AmbientLight has been replaced by EnvironmentMapLight"
)]
pub fn map_ambient_lights(
mut commands: Commands,
mut image_assets: ResMut<Assets<Image>>,
ambient_light: Option<Res<AmbientLight>>,
new_views: Query<
(Entity, Option<Ref<AmbientLight>>),
(
With<Camera3d>,
Without<EnvironmentMapLight>,
Without<EnvironmentMapLightFromAmbientLight>,
),
>,
mut managed_views: Query<
(&mut EnvironmentMapLight, Option<Ref<AmbientLight>>),
With<EnvironmentMapLightFromAmbientLight>,
>,
) {
let ambient_light = ambient_light.map(Into::into);
let ref_ambient_light = ambient_light.as_ref();
for (entity, ambient_override) in new_views.iter() {
let Some(ambient) = ambient_override.as_ref().or(ref_ambient_light) else {
continue;
};
let ambient_required = ambient.brightness > 0.0 && ambient.color != Color::BLACK;
if ambient_required && ambient.is_changed() {
commands
.entity(entity)
.insert(EnvironmentMapLight {
intensity: ambient.brightness,
affects_lightmapped_mesh_diffuse: ambient.affects_lightmapped_meshes,
..EnvironmentMapLight::solid_color(image_assets.as_mut(), ambient.color)
})
.insert(EnvironmentMapLightFromAmbientLight);
}
}
for (mut env_map, ambient_override) in managed_views.iter_mut() {
let Some(ambient) = ambient_override.as_ref().or(ref_ambient_light) else {
continue;
};
let ambient_required = ambient.brightness > 0.0 && ambient.color != Color::BLACK;
if ambient_required && ambient.is_changed() {
*env_map = EnvironmentMapLight {
intensity: ambient.brightness,
affects_lightmapped_mesh_diffuse: ambient.affects_lightmapped_meshes,
..EnvironmentMapLight::solid_color(image_assets.as_mut(), ambient.color)
};
}
}
}

fn shrink_entities(visible_entities: &mut Vec<Entity>) {
// Check that visible entities capacity() is no more than two times greater than len()
let capacity = visible_entities.capacity();
Expand Down
80 changes: 76 additions & 4 deletions crates/bevy_light/src/probe.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use bevy_asset::Handle;
use bevy_asset::{uuid_handle, Assets, Handle, RenderAssetUsages};
use bevy_camera::visibility::Visibility;
use bevy_color::{Color, ColorToPacked, Srgba};
use bevy_ecs::prelude::*;
use bevy_image::Image;
use bevy_math::Quat;
use bevy_reflect::prelude::*;
use bevy_transform::components::Transform;
use wgpu_types::{
Extent3d, TextureDimension, TextureFormat, TextureViewDescriptor, TextureViewDimension,
};

/// A marker component for a light probe, which is a cuboid region that provides
/// global illumination to all fragments inside it.
Expand Down Expand Up @@ -96,14 +100,82 @@ pub struct EnvironmentMapLight {
pub affects_lightmapped_mesh_diffuse: bool,
}

impl EnvironmentMapLight {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't comment on the struct definition above, but I think we need a #[doc(alias = "ambient")] or something similar to point users towards this in our docs.

/// An environment map with a uniform color, useful for uniform ambient lighting.
pub fn solid_color(assets: &mut Assets<Image>, color: Color) -> Self {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I don't have an obvious alternative pattern to use here but for some reason constructors that accept asset collections feels awkward to me. part of me feels like a impl From<Color> for Image would be better:

EnvironmentLightMap::from_image(images.add(Color::WHITE));

but that wouldn't work for the gradient version. Although maybe would if there was some kind of gradient type in bevy_color.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn solid_color(assets: &mut Assets<Image>, color: Color) -> Self {
pub fn solid_color(assets: &mut Assets<Image>, color: impl Into<Color>) -> Self {

so that e.g. tailwind::AMBER_100 works :)

Self::hemispherical_gradient(assets, color, color, color)
}

/// An environment map with a hemispherical gradient, fading between the sky and ground colors
/// at the horizon. Useful as a very simple 'sky'.
pub fn hemispherical_gradient(
assets: &mut Assets<Image>,
top_color: Color,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider making mid_color a parameter too

mid_color: Color,
bottom_color: Color,
Comment on lines +113 to +115

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plz turn these into impl Into<Color> too

) -> Self {
let handle = assets.add(Self::hemispherical_gradient_cubemap(
top_color,
mid_color,
bottom_color,
));

Self {
diffuse_map: handle.clone(),
specular_map: handle,
..Default::default()
}
}

pub(crate) fn hemispherical_gradient_cubemap(
top_color: Color,
mid_color: Color,
bottom_color: Color,
) -> Image {
let top_color: Srgba = top_color.into();
let mid_color: Srgba = mid_color.into();
let bottom_color: Srgba = bottom_color.into();
Image {
texture_view_descriptor: Some(TextureViewDescriptor {
dimension: Some(TextureViewDimension::Cube),
..Default::default()
}),
..Image::new(
Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 6,
},
TextureDimension::D2,
[
mid_color,
mid_color,
top_color,
bottom_color,
mid_color,
mid_color,
]
.into_iter()
.flat_map(Srgba::to_u8_array)
.collect(),
TextureFormat::Rgba8UnormSrgb,
RenderAssetUsages::RENDER_WORLD,
)
}
}
}

pub const DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE: Handle<Image> =
uuid_handle!("99e3f21e-9c08-4924-9895-fa8599416316");

impl Default for EnvironmentMapLight {
fn default() -> Self {
EnvironmentMapLight {
diffuse_map: Handle::default(),
specular_map: Handle::default(),
diffuse_map: DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE,
specular_map: DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE,
intensity: 0.0,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be made non-zero

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah

rotation: Quat::IDENTITY,
affects_lightmapped_mesh_diffuse: true,
affects_lightmapped_mesh_diffuse: false,
}
}
}
Expand Down
Loading
Loading