From 0b5302d96a7ab6d2bff99c43232a1781a97d51c8 Mon Sep 17 00:00:00 2001 From: Shaye Garg <64652557+SparkyPotato@users.noreply.github.com> Date: Tue, 4 Mar 2025 01:40:53 -0600 Subject: [PATCH] Replace Ambient Lights with Environment Map Lights (#17482) # Objective Transparently uses simple `EnvironmentMapLight`s to mimic `AmbientLight`s. Implements the first part of #17468, but I can implement hemispherical lights in this PR too if needed. ## Solution - A function `EnvironmentMapLight::solid_color(&mut Assets, Color)` is provided to make an environment light with a solid color. - A new system is added to `SimulationLightSystems` that maps `AmbientLight`s on views or the world to a corresponding `EnvironmentMapLight`. I have never worked with (or on) Bevy before, so nitpicky comments on how I did things are appreciated :). ## Testing Testing was done on a modified version of the `3d/lighting` example, where I removed all lights except the ambient light. I have not included the example, but can if required. ## Migration `bevy_pbr::AmbientLight` has been deprecated, so all usages of it should be replaced by a `bevy_pbr::EnvironmentMapLight` created with `EnvironmentMapLight::solid_color` placed on the camera. There is no alternative to ambient lights as resources. --- crates/bevy_pbr/src/lib.rs | 22 +++-- crates/bevy_pbr/src/light/ambient_light.rs | 5 ++ crates/bevy_pbr/src/light/mod.rs | 59 ++++++++++++- .../src/light_probe/environment_map.rs | 85 ++++++++++++++++++- crates/bevy_pbr/src/render/light.rs | 26 ++---- .../bevy_pbr/src/render/mesh_view_types.wgsl | 1 - crates/bevy_pbr/src/render/pbr_ambient.wgsl | 29 ------- crates/bevy_pbr/src/render/pbr_functions.wgsl | 15 ---- examples/2d/custom_gltf_vertex_attribute.rs | 14 +-- examples/3d/auto_exposure.rs | 10 +-- examples/3d/fog.rs | 4 + examples/3d/fog_volumes.rs | 4 + examples/3d/irradiance_volumes.rs | 34 +++++--- examples/3d/lighting.rs | 12 ++- examples/3d/lightmaps.rs | 4 + examples/3d/mixed_lighting.rs | 27 +++--- examples/3d/motion_blur.rs | 11 ++- examples/3d/skybox.rs | 22 ++--- examples/3d/specular_tint.rs | 10 +-- examples/3d/spherical_area_lights.rs | 9 +- examples/3d/spotlight.rs | 9 +- examples/3d/ssao.rs | 9 +- examples/3d/transmission.rs | 9 +- examples/3d/volumetric_fog.rs | 4 + examples/animation/animated_mesh.rs | 10 +-- examples/animation/animated_mesh_control.rs | 10 +-- examples/animation/animated_mesh_events.rs | 10 +-- examples/animation/animated_transform.rs | 10 +-- examples/animation/animation_graph.rs | 10 +-- examples/animation/animation_masks.rs | 12 +-- examples/animation/custom_skinned_mesh.rs | 9 +- examples/animation/gltf_skinned_mesh.rs | 14 +-- examples/animation/morph_targets.rs | 14 +-- examples/asset/multi_asset_sync.rs | 10 +-- examples/math/render_primitives.rs | 17 ++-- 35 files changed, 348 insertions(+), 212 deletions(-) delete mode 100644 crates/bevy_pbr/src/render/pbr_ambient.wgsl diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 543a4665fc..75f0458147 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -71,10 +71,16 @@ pub use volumetric_fog::{FogVolume, VolumetricFog, VolumetricFogPlugin, Volumetr /// /// This includes the most common types in this crate, re-exported for your convenience. pub mod prelude { + #[expect( + deprecated, + reason = "AmbientLight has been replaced by EnvironmentMapLight" + )] + #[doc(hidden)] + pub use crate::light::AmbientLight; #[doc(hidden)] pub use crate::{ fog::{DistanceFog, FogFalloff}, - light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight}, + light::{light_consts, DirectionalLight, PointLight, SpotLight}, light_probe::{environment_map::EnvironmentMapLight, LightProbe}, material::{Material, MaterialPlugin}, mesh_material::MeshMaterial3d, @@ -165,7 +171,6 @@ pub const PBR_PREPASS_SHADER_HANDLE: Handle = weak_handle!("9afeaeab-7c45-43ce-b322-4b97799eaeb9"); pub const PBR_FUNCTIONS_HANDLE: Handle = weak_handle!("815b8618-f557-4a96-91a5-a2fb7e249fb0"); -pub const PBR_AMBIENT_HANDLE: Handle = weak_handle!("4a90b95b-112a-4a10-9145-7590d6f14260"); pub const PARALLAX_MAPPING_SHADER_HANDLE: Handle = weak_handle!("6cf57d9f-222a-429a-bba4-55ba9586e1d4"); pub const VIEW_TRANSFORMATIONS_SHADER_HANDLE: Handle = @@ -280,12 +285,6 @@ impl Plugin for PbrPlugin { "render/rgb9e5.wgsl", Shader::from_wgsl ); - load_internal_asset!( - app, - PBR_AMBIENT_HANDLE, - "render/pbr_ambient.wgsl", - Shader::from_wgsl - ); load_internal_asset!( app, PBR_FRAGMENT_HANDLE, @@ -325,6 +324,10 @@ impl Plugin for PbrPlugin { Shader::from_wgsl ); + #[expect( + deprecated, + reason = "AmbientLight has been replaced by EnvironmentMapLight" + )] app.register_asset_reflect::() .register_type::() .register_type::() @@ -401,6 +404,9 @@ impl Plugin for PbrPlugin { .add_systems( PostUpdate, ( + map_ambient_lights + .in_set(SimulationLightSystems::MapAmbientLights) + .after(CameraUpdateSystem), add_clusters .in_set(SimulationLightSystems::AddClusters) .after(CameraUpdateSystem), diff --git a/crates/bevy_pbr/src/light/ambient_light.rs b/crates/bevy_pbr/src/light/ambient_light.rs index f09bab51f6..14ab9a8b1f 100644 --- a/crates/bevy_pbr/src/light/ambient_light.rs +++ b/crates/bevy_pbr/src/light/ambient_light.rs @@ -1,3 +1,8 @@ +#![deprecated( + since = "0.16.0", + note = "Use `EnvironmentMapLight::solid_color` instead" +)] + use super::*; /// An ambient light, which lights the entire scene equally. diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 1c9dc61374..68d01ea656 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -20,9 +20,13 @@ use bevy_render::{ use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::Parallel; -use crate::*; +use crate::{prelude::EnvironmentMapLight, *}; mod ambient_light; +#[expect( + deprecated, + reason = "AmbientLight has been replaced by EnvironmentMapLight" +)] pub use ambient_light::AmbientLight; mod point_light; @@ -509,6 +513,7 @@ pub struct LightVisibilityClass; /// 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: @@ -522,6 +527,58 @@ 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>, + ambient_light: Res, + new_views: Query< + (Entity, Option>), + ( + With, + Without, + Without, + ), + >, + mut managed_views: Query< + (&mut EnvironmentMapLight, Option>), + With, + >, +) { + let ambient_light = ambient_light.into(); + for (entity, ambient_override) in new_views.iter() { + let ambient = ambient_override.as_ref().unwrap_or(&ambient_light); + 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 ambient = ambient_override.as_ref().unwrap_or(&ambient_light); + 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) + }; + } + } +} + pub fn update_directional_light_frusta( mut views: Query< ( diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_pbr/src/light_probe/environment_map.rs index 8069f2acac..fcc1b64a97 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -44,7 +44,8 @@ //! //! [several pre-filtered environment maps]: https://github.com/KhronosGroup/glTF-Sample-Environments -use bevy_asset::{weak_handle, AssetId, Handle}; +use bevy_asset::{weak_handle, AssetId, Assets, Handle, RenderAssetUsages}; +use bevy_color::{Color, ColorToPacked, Srgba}; use bevy_ecs::{ component::Component, query::QueryItem, reflect::ReflectComponent, system::lifetimeless::Read, }; @@ -56,8 +57,9 @@ use bevy_render::{ render_asset::RenderAssets, render_resource::{ binding_types::{self, uniform_buffer}, - BindGroupLayoutEntryBuilder, Sampler, SamplerBindingType, Shader, ShaderStages, - TextureSampleType, TextureView, + BindGroupLayoutEntryBuilder, Extent3d, Sampler, SamplerBindingType, Shader, ShaderStages, + TextureDimension, TextureFormat, TextureSampleType, TextureView, TextureViewDescriptor, + TextureViewDimension, }, renderer::{RenderAdapter, RenderDevice}, texture::{FallbackImage, GpuImage}, @@ -114,6 +116,83 @@ pub struct EnvironmentMapLight { pub affects_lightmapped_mesh_diffuse: bool, } +impl EnvironmentMapLight { + /// An environment map with a uniform color, useful for uniform ambient lighting. + pub fn solid_color(assets: &mut Assets, color: Color) -> Self { + let color: Srgba = color.into(); + let image = Image { + texture_view_descriptor: Some(TextureViewDescriptor { + dimension: Some(TextureViewDimension::Cube), + ..Default::default() + }), + ..Image::new_fill( + Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 6, + }, + TextureDimension::D2, + &color.to_u8_array(), + TextureFormat::Rgba8UnormSrgb, + RenderAssetUsages::RENDER_WORLD, + ) + }; + let handle = assets.add(image); + + Self { + diffuse_map: handle.clone(), + specular_map: handle, + ..Default::default() + } + } + + /// 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, + top_color: Color, + bottom_color: Color, + ) -> Self { + let top_color: Srgba = top_color.into(); + let bottom_color: Srgba = bottom_color.into(); + let mid_color = (top_color + bottom_color) / 2.0; + let image = 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, + ) + }; + let handle = assets.add(image); + + Self { + diffuse_map: handle.clone(), + specular_map: handle, + ..Default::default() + } + } +} + impl Default for EnvironmentMapLight { fn default() -> Self { EnvironmentMapLight { diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index c17b9d9355..9b43c33acf 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -139,7 +139,6 @@ bitflags::bitflags! { #[derive(Copy, Clone, Debug, ShaderType)] pub struct GpuLights { directional_lights: [GpuDirectionalLight; MAX_DIRECTIONAL_LIGHTS], - ambient_color: Vec4, // xyz are x/y/z cluster dimensions and w is the number of clusters cluster_dimensions: UVec4, // xy are vec2(cluster_dimensions.xy) / vec2(view.width, view.height) @@ -149,7 +148,6 @@ pub struct GpuLights { n_directional_lights: u32, // offset from spot light's light index to spot light's shadow map index spot_light_shadowmap_offset: i32, - ambient_light_affects_lightmapped_meshes: u32, } // NOTE: When running bevy on Adreno GPU chipsets in WebGL, any value above 1 will result in a crash @@ -729,11 +727,9 @@ pub fn prepare_lights( &ExtractedClusterConfig, Option<&RenderLayers>, Has, - Option<&AmbientLight>, ), With, >, - ambient_light: Res, point_light_shadow_map: Res, directional_light_shadow_map: Res, mut shadow_render_phases: ResMut>, @@ -1142,18 +1138,11 @@ pub fn prepare_lights( let mut live_views = EntityHashSet::with_capacity(views_count); // set up light data for each view - for ( - entity, - camera_main_entity, - extracted_view, - clusters, - maybe_layers, - no_indirect_drawing, - maybe_ambient_override, - ) in sorted_cameras - .0 - .iter() - .filter_map(|sorted_camera| views.get(sorted_camera.entity).ok()) + for (entity, camera_main_entity, extracted_view, clusters, maybe_layers, no_indirect_drawing) in + sorted_cameras + .0 + .iter() + .filter_map(|sorted_camera| views.get(sorted_camera.entity).ok()) { live_views.insert(entity); @@ -1175,11 +1164,8 @@ pub fn prepare_lights( ); let n_clusters = clusters.dimensions.x * clusters.dimensions.y * clusters.dimensions.z; - let ambient_light = maybe_ambient_override.unwrap_or(&ambient_light); let mut gpu_lights = GpuLights { directional_lights: gpu_directional_lights, - ambient_color: Vec4::from_slice(&LinearRgba::from(ambient_light.color).to_f32_array()) - * ambient_light.brightness, cluster_factors: Vec4::new( clusters.dimensions.x as f32 / extracted_view.viewport.z as f32, clusters.dimensions.y as f32 / extracted_view.viewport.w as f32, @@ -1194,8 +1180,6 @@ pub fn prepare_lights( // index to shadow map index, we need to subtract point light count and add directional shadowmap count. spot_light_shadowmap_offset: num_directional_cascades_enabled as i32 - point_light_count as i32, - ambient_light_affects_lightmapped_meshes: ambient_light.affects_lightmapped_meshes - as u32, }; // TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index 6db72759df..cd46708e74 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -50,7 +50,6 @@ const DIRECTIONAL_LIGHT_FLAGS_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE_BIT: u32 = 4u; struct Lights { // NOTE: this array size must be kept in sync with the constants defined in bevy_pbr/src/render/light.rs directional_lights: array, - ambient_color: vec4, // x/y/z dimensions and n_clusters in w cluster_dimensions: vec4, // xy are vec2(cluster_dimensions.xy) / vec2(view.width, view.height) diff --git a/crates/bevy_pbr/src/render/pbr_ambient.wgsl b/crates/bevy_pbr/src/render/pbr_ambient.wgsl deleted file mode 100644 index 7b174da35c..0000000000 --- a/crates/bevy_pbr/src/render/pbr_ambient.wgsl +++ /dev/null @@ -1,29 +0,0 @@ -#define_import_path bevy_pbr::ambient - -#import bevy_pbr::{ - lighting::{EnvBRDFApprox, F_AB}, - mesh_view_bindings::lights, -} - -// A precomputed `NdotV` is provided because it is computed regardless, -// but `world_normal` and the view vector `V` are provided separately for more advanced uses. -fn ambient_light( - world_position: vec4, - world_normal: vec3, - V: vec3, - NdotV: f32, - diffuse_color: vec3, - specular_color: vec3, - perceptual_roughness: f32, - occlusion: vec3, -) -> vec3 { - let diffuse_ambient = EnvBRDFApprox(diffuse_color, F_AB(1.0, NdotV)); - let specular_ambient = EnvBRDFApprox(specular_color, F_AB(perceptual_roughness, NdotV)); - - // No real world material has specular values under 0.02, so we use this range as a - // "pre-baked specular occlusion" that extinguishes the fresnel term, for artistic control. - // See: https://google.github.io/filament/Filament.html#specularocclusion - let specular_occlusion = saturate(dot(specular_color, vec3(50.0 * 0.33))); - - return (diffuse_ambient + specular_ambient * specular_occlusion) * lights.ambient_color.rgb * occlusion; -} diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index e9b4e1f1a8..72d8ed35dc 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -561,18 +561,6 @@ fn apply_pbr_lighting( #endif } -#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION - // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated - // world position, inverted normal and view vectors, and the following simplified - // values for a fully diffuse transmitted light contribution approximation: - // - // perceptual_roughness = 1.0; - // NdotV = 1.0; - // F0 = vec3(0.0) - // diffuse_occlusion = vec3(1.0) - transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3(0.0), 1.0, vec3(1.0)); -#endif - // Diffuse indirect lighting can come from a variety of sources. The // priority goes like this: // @@ -644,9 +632,6 @@ fn apply_pbr_lighting( #endif // ENVIRONMENT_MAP - // Ambient light (indirect) - indirect_light += ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion); - // we'll use the specular component of the transmitted environment // light in the call to `specular_transmissive_light()` below var specular_transmitted_environment_light = vec3(0.0); diff --git a/examples/2d/custom_gltf_vertex_attribute.rs b/examples/2d/custom_gltf_vertex_attribute.rs index 0742e3616f..903898ce7f 100644 --- a/examples/2d/custom_gltf_vertex_attribute.rs +++ b/examples/2d/custom_gltf_vertex_attribute.rs @@ -24,11 +24,6 @@ const ATTRIBUTE_BARYCENTRIC: MeshVertexAttribute = fn main() { App::new() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 1.0 / 5.0f32, - ..default() - }) .add_plugins(( DefaultPlugins.set( GltfPlugin::default() @@ -48,6 +43,7 @@ fn setup( mut commands: Commands, asset_server: Res, mut materials: ResMut>, + mut images: ResMut>, ) { // Add a mesh loaded from a glTF file. This mesh has data for `ATTRIBUTE_BARYCENTRIC`. let mesh = asset_server.load( @@ -63,7 +59,13 @@ fn setup( Transform::from_scale(150.0 * Vec3::ONE), )); - commands.spawn(Camera2d); + commands.spawn(( + Camera2d, + EnvironmentMapLight { + intensity: 1.0 / 5.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, + )); } /// This custom material uses barycentric coordinates from diff --git a/examples/3d/auto_exposure.rs b/examples/3d/auto_exposure.rs index 79fece61c8..027d06fa4f 100644 --- a/examples/3d/auto_exposure.rs +++ b/examples/3d/auto_exposure.rs @@ -101,11 +101,11 @@ fn setup( } } - commands.insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 0.0, - ..default() - }); + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] + commands.insert_resource(AmbientLight::NONE); commands.spawn(( PointLight { diff --git a/examples/3d/fog.rs b/examples/3d/fog.rs index 9793ae0ad3..0f713b5cdd 100644 --- a/examples/3d/fog.rs +++ b/examples/3d/fog.rs @@ -21,6 +21,10 @@ use bevy::{ }; fn main() { + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] App::new() .insert_resource(AmbientLight::NONE) .add_plugins(DefaultPlugins) diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 68fc6d0ea7..189a397894 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -13,6 +13,10 @@ use bevy::{ /// Entry point. fn main() { + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { diff --git a/examples/3d/irradiance_volumes.rs b/examples/3d/irradiance_volumes.rs index 31529c4219..dffe5fb9bf 100644 --- a/examples/3d/irradiance_volumes.rs +++ b/examples/3d/irradiance_volumes.rs @@ -157,11 +157,6 @@ fn main() { .add_plugins(MaterialPlugin::::default()) .init_resource::() .init_resource::() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 0.0, - ..default() - }) .add_systems(Startup, setup) .add_systems(PreUpdate, create_cubes) .add_systems(Update, rotate_camera) @@ -216,9 +211,14 @@ fn main() { } // Spawns all the scene objects. -fn setup(mut commands: Commands, assets: Res, app_status: Res) { +fn setup( + mut commands: Commands, + images: ResMut>, + assets: Res, + app_status: Res, +) { spawn_main_scene(&mut commands, &assets); - spawn_camera(&mut commands, &assets); + spawn_camera(&mut commands, images, &assets); spawn_irradiance_volume(&mut commands, &assets); spawn_light(&mut commands); spawn_sphere(&mut commands, &assets); @@ -231,7 +231,11 @@ fn spawn_main_scene(commands: &mut Commands, assets: &ExampleAssets) { commands.spawn(SceneRoot(assets.main_scene.clone())); } -fn spawn_camera(commands: &mut Commands, assets: &ExampleAssets) { +fn spawn_camera( + commands: &mut Commands, + mut images: ResMut>, + assets: &ExampleAssets, +) { commands.spawn(( Camera3d::default(), Transform::from_xyz(-10.012, 4.8605, 13.281).looking_at(Vec3::ZERO, Vec3::Y), @@ -240,6 +244,10 @@ fn spawn_camera(commands: &mut Commands, assets: &ExampleAssets) { brightness: 150.0, ..default() }, + EnvironmentMapLight { + intensity: 0.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); } @@ -415,7 +423,7 @@ fn toggle_irradiance_volumes( light_probe_query: Query>, mut app_status: ResMut, assets: Res, - mut ambient_light: ResMut, + mut ambient_light: Query<&mut EnvironmentMapLight>, ) { if !keyboard.just_pressed(KeyCode::Space) { return; @@ -427,7 +435,9 @@ fn toggle_irradiance_volumes( if app_status.irradiance_volume_present { commands.entity(light_probe).remove::(); - ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY; + for mut light in ambient_light.iter_mut() { + light.intensity = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY; + } app_status.irradiance_volume_present = false; } else { commands.entity(light_probe).insert(IrradianceVolume { @@ -435,7 +445,9 @@ fn toggle_irradiance_volumes( intensity: IRRADIANCE_VOLUME_INTENSITY, ..default() }); - ambient_light.brightness = 0.0; + for mut light in ambient_light.iter_mut() { + light.intensity = 0.0; + } app_status.irradiance_volume_present = true; } } diff --git a/examples/3d/lighting.rs b/examples/3d/lighting.rs index b8d7883763..226a8f90b7 100644 --- a/examples/3d/lighting.rs +++ b/examples/3d/lighting.rs @@ -35,6 +35,7 @@ fn setup( parameters: Res, mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, asset_server: Res, ) { @@ -110,13 +111,6 @@ fn setup( Movable, )); - // ambient light - commands.insert_resource(AmbientLight { - color: ORANGE_RED.into(), - brightness: 0.02, - ..default() - }); - // red point light commands.spawn(( PointLight { @@ -236,6 +230,10 @@ fn setup( Camera3d::default(), Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), Exposure::from_physical_camera(**parameters), + EnvironmentMapLight { + intensity: 0.02, + ..EnvironmentMapLight::solid_color(&mut images, ORANGE_RED.into()) + }, )); } diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs index 975b37d7f2..824b548687 100644 --- a/examples/3d/lightmaps.rs +++ b/examples/3d/lightmaps.rs @@ -25,6 +25,10 @@ fn main() { let args: Args = Args::from_args(&[], &[]).unwrap(); let mut app = App::new(); + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] app.add_plugins(DefaultPlugins) .insert_resource(AmbientLight::NONE); diff --git a/examples/3d/mixed_lighting.rs b/examples/3d/mixed_lighting.rs index f7ebbd5cfc..49a1c2f097 100644 --- a/examples/3d/mixed_lighting.rs +++ b/examples/3d/mixed_lighting.rs @@ -123,11 +123,6 @@ fn main() { ..default() })) .add_plugins(MeshPickingPlugin) - .insert_resource(AmbientLight { - color: ClearColor::default().0, - brightness: 10000.0, - affects_lightmapped_meshes: true, - }) .init_resource::() .add_event::>() .add_event::() @@ -145,18 +140,28 @@ fn main() { } /// Creates the scene. -fn setup(mut commands: Commands, asset_server: Res, app_status: Res) { - spawn_camera(&mut commands); +fn setup( + mut commands: Commands, + images: ResMut>, + asset_server: Res, + app_status: Res, +) { + spawn_camera(&mut commands, images); spawn_scene(&mut commands, &asset_server); spawn_buttons(&mut commands); spawn_help_text(&mut commands, &app_status); } /// Spawns the 3D camera. -fn spawn_camera(commands: &mut Commands) { - commands - .spawn(Camera3d::default()) - .insert(Transform::from_xyz(-0.7, 0.7, 1.0).looking_at(vec3(0.0, 0.3, 0.0), Vec3::Y)); +fn spawn_camera(commands: &mut Commands, mut images: ResMut>) { + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(-0.7, 0.7, 1.0).looking_at(vec3(0.0, 0.3, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 10000.0, + ..EnvironmentMapLight::solid_color(&mut images, ClearColor::default().0) + }, + )); } /// Spawns the scene. diff --git a/examples/3d/motion_blur.rs b/examples/3d/motion_blur.rs index 68bb556c6b..3d3cbab2c9 100644 --- a/examples/3d/motion_blur.rs +++ b/examples/3d/motion_blur.rs @@ -17,7 +17,7 @@ fn main() { .run(); } -fn setup_camera(mut commands: Commands) { +fn setup_camera(mut commands: Commands, mut images: ResMut>) { commands.spawn(( Camera3d::default(), // Add the `MotionBlur` component to a camera to enable motion blur. @@ -32,6 +32,10 @@ fn setup_camera(mut commands: Commands) { // MSAA and Motion Blur together are not compatible on WebGL #[cfg(all(feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu")))] Msaa::Off, + EnvironmentMapLight { + intensity: 300.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); } @@ -59,11 +63,6 @@ fn setup_scene( mut meshes: ResMut>, mut materials: ResMut>, ) { - commands.insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 300.0, - ..default() - }); commands.insert_resource(CameraMode::Chase); commands.spawn(( DirectionalLight { diff --git a/examples/3d/skybox.rs b/examples/3d/skybox.rs index dd797473bf..9c009eb8d2 100644 --- a/examples/3d/skybox.rs +++ b/examples/3d/skybox.rs @@ -57,7 +57,11 @@ struct Cubemap { image_handle: Handle, } -fn setup(mut commands: Commands, asset_server: Res) { +fn setup( + mut commands: Commands, + asset_server: Res, + mut images: ResMut>, +) { // directional 'sun' light commands.spawn(( DirectionalLight { @@ -78,17 +82,15 @@ fn setup(mut commands: Commands, asset_server: Res) { brightness: 1000.0, ..default() }, + // This should ideally be using a convolved environment map for diffuse, but for simplicity + // we're just using a solid color here. + EnvironmentMapLight { + intensity: 1.0, + specular_map: skybox_handle.clone(), + ..EnvironmentMapLight::solid_color(&mut images, Color::srgb_u8(210, 220, 240)) + }, )); - // ambient light - // NOTE: The ambient light is used to scale how bright the environment map is so with a bright - // environment map, use an appropriate color and brightness to match - commands.insert_resource(AmbientLight { - color: Color::srgb_u8(210, 220, 240), - brightness: 1.0, - ..default() - }); - commands.insert_resource(Cubemap { is_loaded: false, index: 0, diff --git a/examples/3d/specular_tint.rs b/examples/3d/specular_tint.rs index 5dc362b9c1..6954a02049 100644 --- a/examples/3d/specular_tint.rs +++ b/examples/3d/specular_tint.rs @@ -49,6 +49,10 @@ enum TintType { /// The entry point. fn main() { + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { @@ -59,11 +63,7 @@ fn main() { })) .init_resource::() .init_resource::() - .insert_resource(AmbientLight { - color: Color::BLACK, - brightness: 0.0, - ..default() - }) + .insert_resource(AmbientLight::NONE) .add_systems(Startup, setup) .add_systems(Update, rotate_camera) .add_systems(Update, (toggle_specular_map, update_text).chain()) diff --git a/examples/3d/spherical_area_lights.rs b/examples/3d/spherical_area_lights.rs index c3e945a8f3..9c7c1486e8 100644 --- a/examples/3d/spherical_area_lights.rs +++ b/examples/3d/spherical_area_lights.rs @@ -4,10 +4,6 @@ use bevy::prelude::*; fn main() { App::new() - .insert_resource(AmbientLight { - brightness: 60.0, - ..default() - }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); @@ -16,12 +12,17 @@ fn main() { fn setup( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { // camera commands.spawn(( Camera3d::default(), Transform::from_xyz(0.2, 1.5, 2.5).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 60.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // plane diff --git a/examples/3d/spotlight.rs b/examples/3d/spotlight.rs index c92843404e..b713745821 100644 --- a/examples/3d/spotlight.rs +++ b/examples/3d/spotlight.rs @@ -20,10 +20,6 @@ Rotate Camera: Left and Right Arrows"; fn main() { App::new() - .insert_resource(AmbientLight { - brightness: 20.0, - ..default() - }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, (light_sway, movement, rotation)) @@ -37,6 +33,7 @@ struct Movable; fn setup( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { // ground plane @@ -124,6 +121,10 @@ fn setup( ..default() }, Transform::from_xyz(-4.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 20.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); commands.spawn(( diff --git a/examples/3d/ssao.rs b/examples/3d/ssao.rs index 17c54db633..5e3031afb3 100644 --- a/examples/3d/ssao.rs +++ b/examples/3d/ssao.rs @@ -11,10 +11,6 @@ use std::f32::consts::PI; fn main() { App::new() - .insert_resource(AmbientLight { - brightness: 1000., - ..default() - }) .add_plugins((DefaultPlugins, TemporalAntiAliasPlugin)) .add_systems(Startup, setup) .add_systems(Update, update) @@ -24,6 +20,7 @@ fn main() { fn setup( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { commands.spawn(( @@ -36,6 +33,10 @@ fn setup( Msaa::Off, ScreenSpaceAmbientOcclusion::default(), TemporalAntiAliasing::default(), + EnvironmentMapLight { + intensity: 1000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); let material = materials.add(StandardMaterial { diff --git a/examples/3d/transmission.rs b/examples/3d/transmission.rs index 97f1014c22..a0f126fc3c 100644 --- a/examples/3d/transmission.rs +++ b/examples/3d/transmission.rs @@ -42,13 +42,14 @@ use rand::random; fn main() { let mut app = App::new(); + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] app.add_plugins(DefaultPlugins) .insert_resource(ClearColor(Color::BLACK)) .insert_resource(PointLightShadowMap { size: 2048 }) - .insert_resource(AmbientLight { - brightness: 0.0, - ..default() - }) + .insert_resource(AmbientLight::NONE) .add_systems(Startup, setup) .add_systems(Update, (example_control_system, flicker_system)); diff --git a/examples/3d/volumetric_fog.rs b/examples/3d/volumetric_fog.rs index 9cfef624c6..8130c8a3f7 100644 --- a/examples/3d/volumetric_fog.rs +++ b/examples/3d/volumetric_fog.rs @@ -37,6 +37,10 @@ struct MoveBackAndForthHorizontally { } fn main() { + #[expect( + deprecated, + reason = "Once AmbientLight is removed, the resource can be removed" + )] App::new() .add_plugins(DefaultPlugins) .insert_resource(ClearColor(Color::Srgba(Srgba { diff --git a/examples/animation/animated_mesh.rs b/examples/animation/animated_mesh.rs index ecea86fb17..4ac6cb3fde 100644 --- a/examples/animation/animated_mesh.rs +++ b/examples/animation/animated_mesh.rs @@ -9,11 +9,6 @@ const GLTF_PATH: &str = "models/animated/Fox.glb"; fn main() { App::new() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 2000., - ..default() - }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup_mesh_and_animation) .add_systems(Startup, setup_camera_and_environment) @@ -98,12 +93,17 @@ fn play_animation_when_ready( fn setup_camera_and_environment( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { // Camera commands.spawn(( Camera3d::default(), Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 2000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Plane diff --git a/examples/animation/animated_mesh_control.rs b/examples/animation/animated_mesh_control.rs index 0dafd0de11..0bf23a42c5 100644 --- a/examples/animation/animated_mesh_control.rs +++ b/examples/animation/animated_mesh_control.rs @@ -8,11 +8,6 @@ const FOX_PATH: &str = "models/animated/Fox.glb"; fn main() { App::new() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 2000., - ..default() - }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, setup_scene_once_loaded) @@ -30,6 +25,7 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, mut graphs: ResMut>, ) { @@ -52,6 +48,10 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 2000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Plane diff --git a/examples/animation/animated_mesh_events.rs b/examples/animation/animated_mesh_events.rs index 2048f573fd..73b9852408 100644 --- a/examples/animation/animated_mesh_events.rs +++ b/examples/animation/animated_mesh_events.rs @@ -13,11 +13,6 @@ const FOX_PATH: &str = "models/animated/Fox.glb"; fn main() { App::new() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 2000., - ..default() - }) .add_plugins(DefaultPlugins) .init_resource::() .init_resource::() @@ -78,6 +73,7 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, mut graphs: ResMut>, ) { @@ -98,6 +94,10 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 2000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Plane diff --git a/examples/animation/animated_transform.rs b/examples/animation/animated_transform.rs index decb3d34a6..08e7528797 100644 --- a/examples/animation/animated_transform.rs +++ b/examples/animation/animated_transform.rs @@ -10,11 +10,6 @@ use bevy::{ fn main() { App::new() .add_plugins(DefaultPlugins) - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 150.0, - ..default() - }) .add_systems(Startup, setup) .run(); } @@ -22,6 +17,7 @@ fn main() { fn setup( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, mut animations: ResMut>, mut graphs: ResMut>, @@ -30,6 +26,10 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 150.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Light diff --git a/examples/animation/animation_graph.rs b/examples/animation/animation_graph.rs index 76da8a6644..d063f321d0 100644 --- a/examples/animation/animation_graph.rs +++ b/examples/animation/animation_graph.rs @@ -88,11 +88,6 @@ fn main() { (handle_weight_drag, update_ui, sync_weights).chain(), ) .insert_resource(args) - .insert_resource(AmbientLight { - color: WHITE.into(), - brightness: 100.0, - ..default() - }) .run(); } @@ -216,11 +211,16 @@ fn setup_scene( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { commands.spawn(( Camera3d::default(), Transform::from_xyz(-10.0, 5.0, 13.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y), + EnvironmentMapLight { + intensity: 100.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); commands.spawn(( diff --git a/examples/animation/animation_masks.rs b/examples/animation/animation_masks.rs index 72408260d6..131656e82e 100644 --- a/examples/animation/animation_masks.rs +++ b/examples/animation/animation_masks.rs @@ -2,7 +2,7 @@ use bevy::{ animation::{AnimationTarget, AnimationTargetId}, - color::palettes::css::{LIGHT_GRAY, WHITE}, + color::palettes::css::LIGHT_GRAY, prelude::*, }; use std::collections::HashSet; @@ -105,11 +105,6 @@ fn main() { .add_systems(Update, setup_animation_graph_once_loaded) .add_systems(Update, handle_button_toggles) .add_systems(Update, update_ui) - .insert_resource(AmbientLight { - color: WHITE.into(), - brightness: 100.0, - ..default() - }) .init_resource::() .run(); } @@ -120,12 +115,17 @@ fn setup_scene( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { // Spawn the camera. commands.spawn(( Camera3d::default(), Transform::from_xyz(-15.0, 10.0, 20.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y), + EnvironmentMapLight { + intensity: 100.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Spawn the light. diff --git a/examples/animation/custom_skinned_mesh.rs b/examples/animation/custom_skinned_mesh.rs index b091f2dd42..d86e98295a 100644 --- a/examples/animation/custom_skinned_mesh.rs +++ b/examples/animation/custom_skinned_mesh.rs @@ -20,10 +20,6 @@ use rand_chacha::ChaCha8Rng; fn main() { App::new() .add_plugins(DefaultPlugins) - .insert_resource(AmbientLight { - brightness: 3000.0, - ..default() - }) .add_systems(Startup, setup) .add_systems(Update, joint_animation) .run(); @@ -40,6 +36,7 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, mut skinned_mesh_inverse_bindposes_assets: ResMut>, ) { @@ -47,6 +44,10 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(2.5, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 3000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Create inverse bindpose matrices for a skeleton consists of 2 joints diff --git a/examples/animation/gltf_skinned_mesh.rs b/examples/animation/gltf_skinned_mesh.rs index 48f7cd6f39..5f414087fa 100644 --- a/examples/animation/gltf_skinned_mesh.rs +++ b/examples/animation/gltf_skinned_mesh.rs @@ -8,20 +8,24 @@ use bevy::{math::ops, prelude::*, render::mesh::skinning::SkinnedMesh}; fn main() { App::new() .add_plugins(DefaultPlugins) - .insert_resource(AmbientLight { - brightness: 750.0, - ..default() - }) .add_systems(Startup, setup) .add_systems(Update, joint_animation) .run(); } -fn setup(mut commands: Commands, asset_server: Res) { +fn setup( + mut commands: Commands, + asset_server: Res, + mut images: ResMut>, +) { // Create a camera commands.spawn(( Camera3d::default(), Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::new(0.0, 1.0, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 750.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Spawn the first scene in `models/SimpleSkin/SimpleSkin.gltf` diff --git a/examples/animation/morph_targets.rs b/examples/animation/morph_targets.rs index 258059bf55..7c2c9a00ac 100644 --- a/examples/animation/morph_targets.rs +++ b/examples/animation/morph_targets.rs @@ -19,10 +19,6 @@ fn main() { }), ..default() })) - .insert_resource(AmbientLight { - brightness: 150.0, - ..default() - }) .add_systems(Startup, setup) .add_systems(Update, (name_morphs, setup_animations)) .run(); @@ -34,7 +30,11 @@ struct MorphData { mesh: Handle, } -fn setup(asset_server: Res, mut commands: Commands) { +fn setup( + asset_server: Res, + mut commands: Commands, + mut images: ResMut>, +) { commands.insert_resource(MorphData { the_wave: asset_server .load(GltfAssetLabel::Animation(2).from_asset("models/animated/MorphStressTest.gltf")), @@ -56,6 +56,10 @@ fn setup(asset_server: Res, mut commands: Commands) { commands.spawn(( Camera3d::default(), Transform::from_xyz(3.0, 2.1, 10.2).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 150.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); } diff --git a/examples/asset/multi_asset_sync.rs b/examples/asset/multi_asset_sync.rs index cc233eb5fd..c4b4c92684 100644 --- a/examples/asset/multi_asset_sync.rs +++ b/examples/asset/multi_asset_sync.rs @@ -17,11 +17,6 @@ fn main() { App::new() .add_plugins(DefaultPlugins) .init_state::() - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 2000., - ..default() - }) .add_systems(Startup, setup_assets) .add_systems(Startup, setup_scene) .add_systems(Startup, setup_ui) @@ -185,12 +180,17 @@ fn setup_ui(mut commands: Commands) { fn setup_scene( mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, ) { // Camera commands.spawn(( Camera3d::default(), Transform::from_xyz(10.0, 10.0, 15.0).looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), + EnvironmentMapLight { + intensity: 2000.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, )); // Light diff --git a/examples/math/render_primitives.rs b/examples/math/render_primitives.rs index 56633977e6..26246faf79 100644 --- a/examples/math/render_primitives.rs +++ b/examples/math/render_primitives.rs @@ -14,7 +14,7 @@ fn main() { .init_state::(); // cameras - app.add_systems(Startup, (setup_cameras, setup_lights, setup_ambient_light)) + app.add_systems(Startup, (setup_cameras, setup_lights)) .add_systems( Update, ( @@ -292,14 +292,21 @@ const CIRCULAR_SEGMENT: CircularSegment = CircularSegment { }, }; -fn setup_cameras(mut commands: Commands) { +fn setup_cameras(mut commands: Commands, mut images: ResMut>) { let start_in_2d = true; let make_camera = |is_active| Camera { is_active, ..Default::default() }; - commands.spawn((Camera2d, make_camera(start_in_2d))); + commands.spawn(( + Camera2d, + make_camera(start_in_2d), + EnvironmentMapLight { + intensity: 50.0, + ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) + }, + )); commands.spawn(( Camera3d::default(), @@ -308,10 +315,6 @@ fn setup_cameras(mut commands: Commands) { )); } -fn setup_ambient_light(mut ambient_light: ResMut) { - ambient_light.brightness = 50.0; -} - fn setup_lights(mut commands: Commands) { commands.spawn(( PointLight {