diff --git a/crates/bevy_light/Cargo.toml b/crates/bevy_light/Cargo.toml index 6a3807f9bbf46..760826c49adbb 100644 --- a/crates/bevy_light/Cargo.toml +++ b/crates/bevy_light/Cargo.toml @@ -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 = [] diff --git a/crates/bevy_light/src/ambient_light.rs b/crates/bevy_light/src/ambient_light.rs index 92935e7e06d7a..933fb88652780 100644 --- a/crates/bevy_light/src/ambient_light.rs +++ b/crates/bevy_light/src/ambient_light.rs @@ -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::*; @@ -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, } } diff --git a/crates/bevy_light/src/lib.rs b/crates/bevy_light/src/lib.rs index 89d69b81083b8..3a9a2301319d4 100644 --- a/crates/bevy_light/src/lib.rs +++ b/crates/bevy_light/src/lib.rs @@ -1,6 +1,7 @@ #![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::{ @@ -8,9 +9,11 @@ use bevy_camera::{ 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::*; @@ -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}; @@ -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 { @@ -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::() .register_type::() .register_type::() @@ -135,7 +158,6 @@ impl Plugin for LightPlugin { .register_type::() .register_type::() .init_resource::() - .init_resource::() .init_resource::() .init_resource::() .configure_sets( @@ -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) @@ -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::(|| { + EnvironmentMapLight { + intensity: 50.0, + ..Default::default() + } + }); + } + + app.world_mut().resource_mut::>().insert( + &DEFAULT_ENVIRONMENT_MAP_TEXTURE_HANDLE, + EnvironmentMapLight::hemispherical_gradient_cubemap( + Color::WHITE, + Color::WHITE, + Color::WHITE, + ), + ); } } @@ -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 @@ -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: @@ -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>, + ambient_light: Option>, + new_views: Query< + (Entity, Option>), + ( + With, + Without, + Without, + ), + >, + mut managed_views: Query< + (&mut EnvironmentMapLight, Option>), + With, + >, +) { + 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) { // Check that visible entities capacity() is no more than two times greater than len() let capacity = visible_entities.capacity(); diff --git a/crates/bevy_light/src/probe.rs b/crates/bevy_light/src/probe.rs index 29963e11f863f..e1c3cfbc560c5 100644 --- a/crates/bevy_light/src/probe.rs +++ b/crates/bevy_light/src/probe.rs @@ -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. @@ -96,14 +100,82 @@ 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 { + 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, + top_color: Color, + mid_color: Color, + bottom_color: Color, + ) -> 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 = + 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, rotation: Quat::IDENTITY, - affects_lightmapped_mesh_diffuse: true, + affects_lightmapped_mesh_diffuse: false, } } } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 2947927b0cec5..5ffd15d694629 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -49,11 +49,11 @@ 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, IrradianceVolume, LightPlugin, LightProbe, NotShadowCaster, NotShadowReceiver, - PointLight, PointLightShadowMap, PointLightTexture, ShadowFilteringMethod, SpotLight, - SpotLightTexture, TransmittedShadowReceiver, VolumetricFog, VolumetricLight, + light_consts, CascadeShadowConfig, CascadeShadowConfigBuilder, Cascades, ClusteredDecal, + DirectionalLight, DirectionalLightShadowMap, DirectionalLightTexture, FogVolume, + IrradianceVolume, LightPlugin, LightProbe, NotShadowCaster, NotShadowReceiver, PointLight, + PointLightShadowMap, PointLightTexture, ShadowFilteringMethod, SpotLight, SpotLightTexture, + TransmittedShadowReceiver, VolumetricFog, VolumetricLight, }; pub use cluster::*; pub use components::*; @@ -86,10 +86,16 @@ pub mod prelude { pbr_material::StandardMaterial, ssao::ScreenSpaceAmbientOcclusionPlugin, }; + #[expect( + deprecated, + reason = "AmbientLight has been replaced by EnvironmentMapLight" + )] + #[doc(hidden)] + pub use bevy_light::AmbientLight; #[doc(hidden)] pub use bevy_light::{ - light_consts, AmbientLight, DirectionalLight, EnvironmentMapLight, - GeneratedEnvironmentMapLight, LightProbe, PointLight, SpotLight, + light_consts, DirectionalLight, EnvironmentMapLight, GeneratedEnvironmentMapLight, + LightProbe, PointLight, SpotLight, }; } @@ -175,6 +181,9 @@ pub struct PbrPlugin { /// This requires compute shader support and so will be forcibly disabled if /// the platform doesn't support those. pub use_gpu_instance_buffer_builder: bool, + /// Controls if the default environment map light is added to every + /// [`Camera3d`](bevy_core_pipeline::prelude::Camera3d). + pub default_environment_map_light: bool, /// Debugging flags that can optionally be set when constructing the renderer. pub debug_flags: RenderDebugFlags, } @@ -185,6 +194,7 @@ impl Default for PbrPlugin { prepass_enabled: true, add_default_deferred_lighting_plugin: true, use_gpu_instance_buffer_builder: true, + default_environment_map_light: true, debug_flags: RenderDebugFlags::default(), } } @@ -211,7 +221,6 @@ impl Plugin for PbrPlugin { load_shader_library!(app, "render/shadow_sampling.wgsl"); load_shader_library!(app, "render/pbr_functions.wgsl"); load_shader_library!(app, "render/rgb9e5.wgsl"); - load_shader_library!(app, "render/pbr_ambient.wgsl"); load_shader_library!(app, "render/pbr_fragment.wgsl"); load_shader_library!(app, "render/pbr.wgsl"); load_shader_library!(app, "render/pbr_prepass_functions.wgsl"); @@ -239,13 +248,14 @@ impl Plugin for PbrPlugin { ..Default::default() }, ScreenSpaceAmbientOcclusionPlugin, - ExtractResourcePlugin::::default(), FogPlugin, ExtractResourcePlugin::::default(), ExtractComponentPlugin::::default(), LightmapPlugin, LightProbePlugin, - LightPlugin, + LightPlugin { + default_environment_map_light: self.default_environment_map_light, + }, GpuMeshPreprocessPlugin { use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, }, @@ -258,7 +268,6 @@ impl Plugin for PbrPlugin { SyncComponentPlugin::::default(), SyncComponentPlugin::::default(), SyncComponentPlugin::::default(), - ExtractComponentPlugin::::default(), )) .add_plugins(AtmospherePlugin) .configure_sets( diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_pbr/src/light_probe/environment_map.rs index e6dfebd903ad1..d63a5fb2474b7 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -9,10 +9,9 @@ //! entities they're attached to have: //! //! 1. If attached to a view, they represent the objects located a very far -//! distance from the view, in a similar manner to a skybox. Essentially, these -//! *view environment maps* represent a higher-quality replacement for -//! [`AmbientLight`](crate::AmbientLight) for outdoor scenes. The indirect light from such -//! environment maps are added to every point of the scene, including +//! distance from the view, in a similar manner to a skybox. These +//! *view environment maps* provide ambient lighting for outdoor scenes. +//! The indirect light from such environment maps are added to every point of the scene, including //! interior enclosed areas. //! //! 2. If attached to a [`crate::LightProbe`], environment maps represent the immediate diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index bec2a6d1a9597..44029f77a46df 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -147,7 +147,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) @@ -157,7 +156,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 @@ -651,11 +649,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>, @@ -920,7 +916,6 @@ pub fn prepare_lights( _clusters, maybe_layers, _no_indirect_drawing, - _maybe_ambient_override, ) in sorted_cameras .0 .iter() @@ -1051,18 +1046,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); @@ -1085,7 +1073,6 @@ 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_directional_lights = [GpuDirectionalLight::default(); MAX_DIRECTIONAL_LIGHTS]; let mut num_directional_cascades_enabled_for_this_view = 0usize; @@ -1155,8 +1142,6 @@ pub fn prepare_lights( 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, @@ -1170,8 +1155,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 aaf9d0ef7d7e1..8178f1cfd8b45 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 = 1u << 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 7b174da35c9db..0000000000000 --- 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 2c862958dd223..3ab120e8d5cfa 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -558,18 +558,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: // @@ -633,18 +621,6 @@ fn apply_pbr_lighting( } #endif // ENVIRONMENT_MAP - // Ambient light (indirect) - // If we are lightmapped, disable the ambient contribution if requested. - // This is to avoid double-counting ambient light. (It might be part of the lightmap) -#ifdef LIGHTMAP - let enable_ambient = view_bindings::lights.ambient_light_affects_lightmapped_meshes != 0u; -#else // LIGHTMAP - let enable_ambient = true; -#endif // LIGHTMAP - if (enable_ambient) { - 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/crates/bevy_render/src/extract_impls.rs b/crates/bevy_render/src/extract_impls.rs index 87b854363abea..1df8530838b9a 100644 --- a/crates/bevy_render/src/extract_impls.rs +++ b/crates/bevy_render/src/extract_impls.rs @@ -1,9 +1,9 @@ //! This module exists because of the orphan rule use bevy_ecs::query::QueryItem; -use bevy_light::{cluster::ClusteredDecal, AmbientLight, ShadowFilteringMethod}; +use bevy_light::{cluster::ClusteredDecal, ShadowFilteringMethod}; -use crate::{extract_component::ExtractComponent, extract_resource::ExtractResource}; +use crate::extract_component::ExtractComponent; impl ExtractComponent for ClusteredDecal { type QueryData = &'static Self; @@ -14,22 +14,6 @@ impl ExtractComponent for ClusteredDecal { 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 = (); diff --git a/examples/2d/custom_gltf_vertex_attribute.rs b/examples/2d/custom_gltf_vertex_attribute.rs index 0742e3616fe04..6e6d3baa66bfb 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() @@ -63,7 +58,13 @@ fn setup( Transform::from_scale(150.0 * Vec3::ONE), )); - commands.spawn(Camera2d); + commands.spawn(( + Camera2d, + EnvironmentMapLight { + intensity: 1.0 / 5.0, + ..default() + }, + )); } /// This custom material uses barycentric coordinates from diff --git a/examples/3d/auto_exposure.rs b/examples/3d/auto_exposure.rs index 62c875dc5dc8a..acc075ac7a49e 100644 --- a/examples/3d/auto_exposure.rs +++ b/examples/3d/auto_exposure.rs @@ -22,7 +22,10 @@ use bevy::{ fn main() { App::new() - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + })) .add_plugins(AutoExposurePlugin) .add_systems(Startup, setup) .add_systems(Update, example_control_system) @@ -97,12 +100,6 @@ fn setup( } } - commands.insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 0.0, - ..default() - }); - commands.spawn(( PointLight { intensity: 2000.0, diff --git a/examples/3d/fog.rs b/examples/3d/fog.rs index f1fb3f1ed5169..0251d2bcf496a 100644 --- a/examples/3d/fog.rs +++ b/examples/3d/fog.rs @@ -29,8 +29,10 @@ use bevy::{ fn main() { App::new() - .insert_resource(AmbientLight::NONE) - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + })) .add_systems( Startup, (setup_camera_fog, setup_pyramid_scene, setup_instructions), diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 63804ee9dea82..0ec3cbc4b8a1f 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -15,14 +15,20 @@ use bevy::{ /// Entry point. fn main() { App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "Bevy Fog Volumes Example".into(), - ..default() - }), - ..default() - })) - .insert_resource(AmbientLight::NONE) + .add_plugins( + DefaultPlugins + .set(WindowPlugin { + primary_window: Some(Window { + title: "Bevy Fog Volumes Example".into(), + ..default() + }), + ..default() + }) + .set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + }), + ) .add_systems(Startup, setup) .add_systems(Update, rotate_camera) .run(); diff --git a/examples/3d/irradiance_volumes.rs b/examples/3d/irradiance_volumes.rs index 80373512db984..7b72a16695ea4 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) @@ -240,6 +235,10 @@ fn spawn_camera(commands: &mut Commands, assets: &ExampleAssets) { brightness: 150.0, ..default() }, + EnvironmentMapLight { + intensity: 0.0, + ..default() + }, )); } @@ -414,7 +413,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; @@ -426,7 +425,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 { @@ -434,7 +435,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 dfe4815d64c6b..8eb14311d6579 100644 --- a/examples/3d/lighting.rs +++ b/examples/3d/lighting.rs @@ -43,6 +43,7 @@ fn setup( parameters: Res, mut commands: Commands, mut meshes: ResMut>, + mut images: ResMut>, mut materials: ResMut>, asset_server: Res, ) { @@ -118,14 +119,6 @@ fn setup( Movable, )); - // ambient light - // ambient lights' brightnesses are measured in candela per meter square, calculable as (color * brightness) - commands.insert_resource(AmbientLight { - color: ORANGE_RED.into(), - brightness: 200.0, - ..default() - }); - // red point light commands.spawn(( PointLight { @@ -247,6 +240,11 @@ fn setup( Camera3d::default(), Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), Exposure::from_physical_camera(**parameters), + // environment lights' brightnesses are measured in candela per meter square, calculable as (color * intensity) + EnvironmentMapLight { + intensity: 80.0, + ..EnvironmentMapLight::solid_color(&mut images, ORANGE_RED.into()) + }, )); } @@ -290,19 +288,22 @@ fn update_exposure( fn toggle_ambient_light( key_input: Res>, - mut ambient_light: ResMut, + environment_map_lights: Query<&mut EnvironmentMapLight>, text: Single>, mut writer: TextUiWriter, ) { if key_input.just_pressed(KeyCode::Space) { - if ambient_light.brightness > 1. { - ambient_light.brightness = 0.; + let Some(mut light) = environment_map_lights.into_iter().next() else { + return; + }; + if light.intensity > 1. { + light.intensity = 0.; } else { - ambient_light.brightness = 200.; + light.intensity = 80.; } let entity = *text; - let ambient_light_state_text: &str = match ambient_light.brightness { + let ambient_light_state_text: &str = match light.intensity { 0. => "off", _ => "on", }; diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs index c994741150ad3..2bb9d5d2a5b1d 100644 --- a/examples/3d/lightmaps.rs +++ b/examples/3d/lightmaps.rs @@ -26,8 +26,7 @@ fn main() { let args: Args = Args::from_args(&[], &[]).unwrap(); let mut app = App::new(); - app.add_plugins(DefaultPlugins) - .insert_resource(AmbientLight::NONE); + app.add_plugins(DefaultPlugins); if args.deferred { app.insert_resource(DefaultOpaqueRendererMethod::deferred()); diff --git a/examples/3d/mixed_lighting.rs b/examples/3d/mixed_lighting.rs index e2453a6132c76..d294fb4a0f66d 100644 --- a/examples/3d/mixed_lighting.rs +++ b/examples/3d/mixed_lighting.rs @@ -124,11 +124,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::() @@ -146,18 +141,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 529ae85499f11..b85e22f596bc7 100644 --- a/examples/3d/motion_blur.rs +++ b/examples/3d/motion_blur.rs @@ -30,6 +30,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, + ..default() + }, )); } @@ -57,11 +61,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 dd797473bf57d..9c009eb8d2461 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 148f11ba5caf6..d5aab4f82228c 100644 --- a/examples/3d/specular_tint.rs +++ b/examples/3d/specular_tint.rs @@ -50,20 +50,22 @@ enum TintType { /// The entry point. fn main() { App::new() - .add_plugins(DefaultPlugins.set(WindowPlugin { - primary_window: Some(Window { - title: "Bevy Specular Tint Example".into(), - ..default() - }), - ..default() - })) + .add_plugins( + DefaultPlugins + .set(WindowPlugin { + primary_window: Some(Window { + title: "Bevy Specular Tint Example".into(), + ..default() + }), + ..default() + }) + .set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + }), + ) .init_resource::() .init_resource::() - .insert_resource(AmbientLight { - color: Color::BLACK, - brightness: 0.0, - ..default() - }) .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 c3e945a8f3492..54caf3f4edda9 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(); @@ -22,6 +18,10 @@ fn setup( commands.spawn(( Camera3d::default(), Transform::from_xyz(0.2, 1.5, 2.5).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 60.0, + ..default() + }, )); // plane diff --git a/examples/3d/spotlight.rs b/examples/3d/spotlight.rs index 3885f47e65fbf..6e655adfd391f 100644 --- a/examples/3d/spotlight.rs +++ b/examples/3d/spotlight.rs @@ -21,10 +21,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)) @@ -122,6 +118,10 @@ fn setup( Camera3d::default(), Hdr, Transform::from_xyz(-4.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y), + EnvironmentMapLight { + intensity: 20.0, + ..default() + }, )); commands.spawn(( diff --git a/examples/3d/ssao.rs b/examples/3d/ssao.rs index 072c963bef8dd..e70588dd7018e 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) .add_systems(Startup, setup) .add_systems(Update, update) @@ -33,6 +29,10 @@ fn setup( Msaa::Off, ScreenSpaceAmbientOcclusion::default(), TemporalAntiAliasing::default(), + EnvironmentMapLight { + intensity: 1000.0, + ..default() + }, )); let material = materials.add(StandardMaterial { diff --git a/examples/3d/transmission.rs b/examples/3d/transmission.rs index ee62654ea632e..05d461eb27938 100644 --- a/examples/3d/transmission.rs +++ b/examples/3d/transmission.rs @@ -45,13 +45,12 @@ use rand::random; fn main() { App::new() - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + })) .insert_resource(ClearColor(Color::BLACK)) .insert_resource(PointLightShadowMap { size: 2048 }) - .insert_resource(AmbientLight { - brightness: 0.0, - ..default() - }) .add_systems(Startup, setup) .add_systems(Update, (example_control_system, flicker_system)) .run(); diff --git a/examples/3d/volumetric_fog.rs b/examples/3d/volumetric_fog.rs index 1d13e333c9d31..0378374c82876 100644 --- a/examples/3d/volumetric_fog.rs +++ b/examples/3d/volumetric_fog.rs @@ -38,14 +38,16 @@ struct MoveBackAndForthHorizontally { fn main() { App::new() - .add_plugins(DefaultPlugins) + .add_plugins(DefaultPlugins.set(bevy::pbr::PbrPlugin { + default_environment_map_light: false, + ..default() + })) .insert_resource(ClearColor(Color::Srgba(Srgba { red: 0.02, green: 0.02, blue: 0.02, alpha: 1.0, }))) - .insert_resource(AmbientLight::NONE) .init_resource::() .add_systems(Startup, setup) .add_systems(Update, tweak_scene) diff --git a/examples/animation/animated_mesh.rs b/examples/animation/animated_mesh.rs index 06e6c45a58b47..a665771f1b10f 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) @@ -104,6 +99,10 @@ fn setup_camera_and_environment( 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, + ..default() + }, )); // Plane diff --git a/examples/animation/animated_mesh_control.rs b/examples/animation/animated_mesh_control.rs index 0dafd0de11892..ef7f586ed6350 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) @@ -52,6 +47,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, + ..default() + }, )); // Plane diff --git a/examples/animation/animated_mesh_events.rs b/examples/animation/animated_mesh_events.rs index f3b1a2af18a59..4000954cee45f 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::() @@ -98,6 +93,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, + ..default() + }, )); // Plane diff --git a/examples/animation/animated_transform.rs b/examples/animation/animated_transform.rs index decb3d34a69df..cc44ef0d24f69 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(); } @@ -30,6 +25,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, + ..default() + }, )); // Light diff --git a/examples/animation/animation_graph.rs b/examples/animation/animation_graph.rs index e511a1bb7faa4..82623cd95a1ef 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(); } @@ -227,6 +222,10 @@ fn setup_scene( 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, + ..default() + }, )); commands.spawn(( diff --git a/examples/animation/animation_masks.rs b/examples/animation/animation_masks.rs index 613e85eb2fce3..ac0f9babfc976 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(); } @@ -126,6 +121,10 @@ fn setup_scene( 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, + ..default() + }, )); // Spawn the light. diff --git a/examples/animation/custom_skinned_mesh.rs b/examples/animation/custom_skinned_mesh.rs index b091f2dd4254c..abc8c356721de 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(); @@ -47,6 +43,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, + ..default() + }, )); // 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 2e1dd160179b6..27a7683892fd3 100644 --- a/examples/animation/gltf_skinned_mesh.rs +++ b/examples/animation/gltf_skinned_mesh.rs @@ -8,10 +8,6 @@ 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(); @@ -22,6 +18,10 @@ fn setup(mut commands: Commands, asset_server: Res) { 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, + ..default() + }, )); // Spawn the first scene in `models/SimpleSkin/SimpleSkin.gltf` diff --git a/examples/animation/morph_targets.rs b/examples/animation/morph_targets.rs index 258059bf55655..3233035ffbca0 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(); @@ -56,6 +52,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, + ..default() + }, )); } diff --git a/examples/asset/multi_asset_sync.rs b/examples/asset/multi_asset_sync.rs index 83add4ba3c016..7f4146eefb5ec 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) @@ -191,6 +186,10 @@ fn setup_scene( 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, + ..default() + }, )); // Light diff --git a/examples/math/render_primitives.rs b/examples/math/render_primitives.rs index 26be0445baa90..a9c35f90c394c 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, ( @@ -299,7 +299,14 @@ fn setup_cameras(mut commands: Commands) { ..Default::default() }; - commands.spawn((Camera2d, make_camera(start_in_2d))); + commands.spawn(( + Camera2d, + make_camera(start_in_2d), + EnvironmentMapLight { + intensity: 50.0, + ..default() + }, + )); 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 { diff --git a/release-content/migration-guides/AmbientLight_deprecation.md b/release-content/migration-guides/AmbientLight_deprecation.md new file mode 100644 index 0000000000000..fafc9b7bfc0e7 --- /dev/null +++ b/release-content/migration-guides/AmbientLight_deprecation.md @@ -0,0 +1,9 @@ +--- +title: `AmbientLight` deprecated +pull_requests: [18207] +--- + +`AmbientLight`s have been deprecated in favor of using `EnvironmentMapLight`s for the same purpose. +All usages of an ambient light can be replaced by `EnvironmentMapLight::solid_color` added to the camera. +This will render slightly differently, as previously, `AmbientLight`s were (incorrectly) treated as diffuse-only light sources, +while `EnvironmentMapLight`s have both a specular and diffuse component. diff --git a/tests/3d/test_invalid_skinned_mesh.rs b/tests/3d/test_invalid_skinned_mesh.rs index a4567016ed3c5..9993239d87550 100644 --- a/tests/3d/test_invalid_skinned_mesh.rs +++ b/tests/3d/test_invalid_skinned_mesh.rs @@ -18,10 +18,6 @@ use core::f32::consts::TAU; fn main() { App::new() .add_plugins(DefaultPlugins) - .insert_resource(AmbientLight { - brightness: 20_000.0, - ..default() - }) .add_systems(Startup, (setup_environment, setup_meshes)) .add_systems(Update, update_animated_joints) .run(); @@ -30,6 +26,7 @@ fn main() { fn setup_environment( mut commands: Commands, mut mesh_assets: ResMut>, + mut image_assets: ResMut>, mut material_assets: ResMut>, ) { let description = "(left to right)\n\ @@ -58,6 +55,10 @@ fn setup_environment( }, ..OrthographicProjection::default_3d() }), + EnvironmentMapLight { + intensity: 20_000.0, + ..EnvironmentMapLight::solid_color(&mut image_assets, Color::WHITE) + }, // Add motion blur so we can check if it's working for skinned meshes. // This also exercises the renderer's prepass path. MotionBlur {