diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 75f0458147..543a4665fc 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -71,16 +71,10 @@ 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, DirectionalLight, PointLight, SpotLight}, + light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight}, light_probe::{environment_map::EnvironmentMapLight, LightProbe}, material::{Material, MaterialPlugin}, mesh_material::MeshMaterial3d, @@ -171,6 +165,7 @@ 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 = @@ -285,6 +280,12 @@ 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, @@ -324,10 +325,6 @@ impl Plugin for PbrPlugin { Shader::from_wgsl ); - #[expect( - deprecated, - reason = "AmbientLight has been replaced by EnvironmentMapLight" - )] app.register_asset_reflect::() .register_type::() .register_type::() @@ -404,9 +401,6 @@ 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 14ab9a8b1f..f09bab51f6 100644 --- a/crates/bevy_pbr/src/light/ambient_light.rs +++ b/crates/bevy_pbr/src/light/ambient_light.rs @@ -1,8 +1,3 @@ -#![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 68d01ea656..1c9dc61374 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -20,13 +20,9 @@ use bevy_render::{ use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::Parallel; -use crate::{prelude::EnvironmentMapLight, *}; +use crate::*; mod ambient_light; -#[expect( - deprecated, - reason = "AmbientLight has been replaced by EnvironmentMapLight" -)] pub use ambient_light::AmbientLight; mod point_light; @@ -513,7 +509,6 @@ 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: @@ -527,58 +522,6 @@ 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 fcc1b64a97..8069f2acac 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -44,8 +44,7 @@ //! //! [several pre-filtered environment maps]: https://github.com/KhronosGroup/glTF-Sample-Environments -use bevy_asset::{weak_handle, AssetId, Assets, Handle, RenderAssetUsages}; -use bevy_color::{Color, ColorToPacked, Srgba}; +use bevy_asset::{weak_handle, AssetId, Handle}; use bevy_ecs::{ component::Component, query::QueryItem, reflect::ReflectComponent, system::lifetimeless::Read, }; @@ -57,9 +56,8 @@ use bevy_render::{ render_asset::RenderAssets, render_resource::{ binding_types::{self, uniform_buffer}, - BindGroupLayoutEntryBuilder, Extent3d, Sampler, SamplerBindingType, Shader, ShaderStages, - TextureDimension, TextureFormat, TextureSampleType, TextureView, TextureViewDescriptor, - TextureViewDimension, + BindGroupLayoutEntryBuilder, Sampler, SamplerBindingType, Shader, ShaderStages, + TextureSampleType, TextureView, }, renderer::{RenderAdapter, RenderDevice}, texture::{FallbackImage, GpuImage}, @@ -116,83 +114,6 @@ 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 9b43c33acf..c17b9d9355 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -139,6 +139,7 @@ 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) @@ -148,6 +149,7 @@ 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 @@ -727,9 +729,11 @@ 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>, @@ -1138,11 +1142,18 @@ 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) 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, + maybe_ambient_override, + ) in sorted_cameras + .0 + .iter() + .filter_map(|sorted_camera| views.get(sorted_camera.entity).ok()) { live_views.insert(entity); @@ -1164,8 +1175,11 @@ 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, @@ -1180,6 +1194,8 @@ 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 cd46708e74..6db72759df 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -50,6 +50,7 @@ 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 new file mode 100644 index 0000000000..7b174da35c --- /dev/null +++ b/crates/bevy_pbr/src/render/pbr_ambient.wgsl @@ -0,0 +1,29 @@ +#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 72d8ed35dc..e9b4e1f1a8 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -561,6 +561,18 @@ 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: // @@ -632,6 +644,9 @@ 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 903898ce7f..0742e3616f 100644 --- a/examples/2d/custom_gltf_vertex_attribute.rs +++ b/examples/2d/custom_gltf_vertex_attribute.rs @@ -24,6 +24,11 @@ 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() @@ -43,7 +48,6 @@ 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( @@ -59,13 +63,7 @@ fn setup( Transform::from_scale(150.0 * Vec3::ONE), )); - commands.spawn(( - Camera2d, - EnvironmentMapLight { - intensity: 1.0 / 5.0, - ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) - }, - )); + commands.spawn(Camera2d); } /// This custom material uses barycentric coordinates from diff --git a/examples/3d/auto_exposure.rs b/examples/3d/auto_exposure.rs index 027d06fa4f..79fece61c8 100644 --- a/examples/3d/auto_exposure.rs +++ b/examples/3d/auto_exposure.rs @@ -101,11 +101,11 @@ fn setup( } } - #[expect( - deprecated, - reason = "Once AmbientLight is removed, the resource can be removed" - )] - commands.insert_resource(AmbientLight::NONE); + commands.insert_resource(AmbientLight { + color: Color::WHITE, + brightness: 0.0, + ..default() + }); commands.spawn(( PointLight { diff --git a/examples/3d/fog.rs b/examples/3d/fog.rs index 0f713b5cdd..9793ae0ad3 100644 --- a/examples/3d/fog.rs +++ b/examples/3d/fog.rs @@ -21,10 +21,6 @@ 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 189a397894..68fc6d0ea7 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -13,10 +13,6 @@ 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 dffe5fb9bf..31529c4219 100644 --- a/examples/3d/irradiance_volumes.rs +++ b/examples/3d/irradiance_volumes.rs @@ -157,6 +157,11 @@ 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) @@ -211,14 +216,9 @@ fn main() { } // Spawns all the scene objects. -fn setup( - mut commands: Commands, - images: ResMut>, - assets: Res, - app_status: Res, -) { +fn setup(mut commands: Commands, assets: Res, app_status: Res) { spawn_main_scene(&mut commands, &assets); - spawn_camera(&mut commands, images, &assets); + spawn_camera(&mut commands, &assets); spawn_irradiance_volume(&mut commands, &assets); spawn_light(&mut commands); spawn_sphere(&mut commands, &assets); @@ -231,11 +231,7 @@ fn spawn_main_scene(commands: &mut Commands, assets: &ExampleAssets) { commands.spawn(SceneRoot(assets.main_scene.clone())); } -fn spawn_camera( - commands: &mut Commands, - mut images: ResMut>, - assets: &ExampleAssets, -) { +fn spawn_camera(commands: &mut Commands, assets: &ExampleAssets) { commands.spawn(( Camera3d::default(), Transform::from_xyz(-10.012, 4.8605, 13.281).looking_at(Vec3::ZERO, Vec3::Y), @@ -244,10 +240,6 @@ fn spawn_camera( brightness: 150.0, ..default() }, - EnvironmentMapLight { - intensity: 0.0, - ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) - }, )); } @@ -423,7 +415,7 @@ fn toggle_irradiance_volumes( light_probe_query: Query>, mut app_status: ResMut, assets: Res, - mut ambient_light: Query<&mut EnvironmentMapLight>, + mut ambient_light: ResMut, ) { if !keyboard.just_pressed(KeyCode::Space) { return; @@ -435,9 +427,7 @@ fn toggle_irradiance_volumes( if app_status.irradiance_volume_present { commands.entity(light_probe).remove::(); - for mut light in ambient_light.iter_mut() { - light.intensity = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY; - } + ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY; app_status.irradiance_volume_present = false; } else { commands.entity(light_probe).insert(IrradianceVolume { @@ -445,9 +435,7 @@ fn toggle_irradiance_volumes( intensity: IRRADIANCE_VOLUME_INTENSITY, ..default() }); - for mut light in ambient_light.iter_mut() { - light.intensity = 0.0; - } + ambient_light.brightness = 0.0; app_status.irradiance_volume_present = true; } } diff --git a/examples/3d/lighting.rs b/examples/3d/lighting.rs index 226a8f90b7..b8d7883763 100644 --- a/examples/3d/lighting.rs +++ b/examples/3d/lighting.rs @@ -35,7 +35,6 @@ fn setup( parameters: Res, mut commands: Commands, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, asset_server: Res, ) { @@ -111,6 +110,13 @@ fn setup( Movable, )); + // ambient light + commands.insert_resource(AmbientLight { + color: ORANGE_RED.into(), + brightness: 0.02, + ..default() + }); + // red point light commands.spawn(( PointLight { @@ -230,10 +236,6 @@ 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 824b548687..975b37d7f2 100644 --- a/examples/3d/lightmaps.rs +++ b/examples/3d/lightmaps.rs @@ -25,10 +25,6 @@ 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 49a1c2f097..f7ebbd5cfc 100644 --- a/examples/3d/mixed_lighting.rs +++ b/examples/3d/mixed_lighting.rs @@ -123,6 +123,11 @@ 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::() @@ -140,28 +145,18 @@ fn main() { } /// Creates the scene. -fn setup( - mut commands: Commands, - images: ResMut>, - asset_server: Res, - app_status: Res, -) { - spawn_camera(&mut commands, images); +fn setup(mut commands: Commands, asset_server: Res, app_status: Res) { + spawn_camera(&mut commands); 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, 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) - }, - )); +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)); } /// Spawns the scene. diff --git a/examples/3d/motion_blur.rs b/examples/3d/motion_blur.rs index 3d3cbab2c9..68bb556c6b 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, mut images: ResMut>) { +fn setup_camera(mut commands: Commands) { commands.spawn(( Camera3d::default(), // Add the `MotionBlur` component to a camera to enable motion blur. @@ -32,10 +32,6 @@ fn setup_camera(mut commands: Commands, mut images: ResMut>) { // 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) - }, )); } @@ -63,6 +59,11 @@ 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 9c009eb8d2..dd797473bf 100644 --- a/examples/3d/skybox.rs +++ b/examples/3d/skybox.rs @@ -57,11 +57,7 @@ struct Cubemap { image_handle: Handle, } -fn setup( - mut commands: Commands, - asset_server: Res, - mut images: ResMut>, -) { +fn setup(mut commands: Commands, asset_server: Res) { // directional 'sun' light commands.spawn(( DirectionalLight { @@ -82,15 +78,17 @@ fn setup( 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 6954a02049..5dc362b9c1 100644 --- a/examples/3d/specular_tint.rs +++ b/examples/3d/specular_tint.rs @@ -49,10 +49,6 @@ 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 { @@ -63,7 +59,11 @@ fn main() { })) .init_resource::() .init_resource::() - .insert_resource(AmbientLight::NONE) + .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 9c7c1486e8..c3e945a8f3 100644 --- a/examples/3d/spherical_area_lights.rs +++ b/examples/3d/spherical_area_lights.rs @@ -4,6 +4,10 @@ use bevy::prelude::*; fn main() { App::new() + .insert_resource(AmbientLight { + brightness: 60.0, + ..default() + }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); @@ -12,17 +16,12 @@ 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 b713745821..c92843404e 100644 --- a/examples/3d/spotlight.rs +++ b/examples/3d/spotlight.rs @@ -20,6 +20,10 @@ 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)) @@ -33,7 +37,6 @@ struct Movable; fn setup( mut commands: Commands, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, ) { // ground plane @@ -121,10 +124,6 @@ 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 5e3031afb3..17c54db633 100644 --- a/examples/3d/ssao.rs +++ b/examples/3d/ssao.rs @@ -11,6 +11,10 @@ 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) @@ -20,7 +24,6 @@ fn main() { fn setup( mut commands: Commands, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, ) { commands.spawn(( @@ -33,10 +36,6 @@ 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 a0f126fc3c..97f1014c22 100644 --- a/examples/3d/transmission.rs +++ b/examples/3d/transmission.rs @@ -42,14 +42,13 @@ 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::NONE) + .insert_resource(AmbientLight { + brightness: 0.0, + ..default() + }) .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 8130c8a3f7..9cfef624c6 100644 --- a/examples/3d/volumetric_fog.rs +++ b/examples/3d/volumetric_fog.rs @@ -37,10 +37,6 @@ 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 4ac6cb3fde..ecea86fb17 100644 --- a/examples/animation/animated_mesh.rs +++ b/examples/animation/animated_mesh.rs @@ -9,6 +9,11 @@ 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) @@ -93,17 +98,12 @@ 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 0bf23a42c5..0dafd0de11 100644 --- a/examples/animation/animated_mesh_control.rs +++ b/examples/animation/animated_mesh_control.rs @@ -8,6 +8,11 @@ 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) @@ -25,7 +30,6 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, mut graphs: ResMut>, ) { @@ -48,10 +52,6 @@ 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 73b9852408..2048f573fd 100644 --- a/examples/animation/animated_mesh_events.rs +++ b/examples/animation/animated_mesh_events.rs @@ -13,6 +13,11 @@ 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::() @@ -73,7 +78,6 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, mut graphs: ResMut>, ) { @@ -94,10 +98,6 @@ 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 08e7528797..decb3d34a6 100644 --- a/examples/animation/animated_transform.rs +++ b/examples/animation/animated_transform.rs @@ -10,6 +10,11 @@ use bevy::{ fn main() { App::new() .add_plugins(DefaultPlugins) + .insert_resource(AmbientLight { + color: Color::WHITE, + brightness: 150.0, + ..default() + }) .add_systems(Startup, setup) .run(); } @@ -17,7 +22,6 @@ fn main() { fn setup( mut commands: Commands, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, mut animations: ResMut>, mut graphs: ResMut>, @@ -26,10 +30,6 @@ 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 d063f321d0..76da8a6644 100644 --- a/examples/animation/animation_graph.rs +++ b/examples/animation/animation_graph.rs @@ -88,6 +88,11 @@ fn main() { (handle_weight_drag, update_ui, sync_weights).chain(), ) .insert_resource(args) + .insert_resource(AmbientLight { + color: WHITE.into(), + brightness: 100.0, + ..default() + }) .run(); } @@ -211,16 +216,11 @@ 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 131656e82e..72408260d6 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, + color::palettes::css::{LIGHT_GRAY, WHITE}, prelude::*, }; use std::collections::HashSet; @@ -105,6 +105,11 @@ 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(); } @@ -115,17 +120,12 @@ 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 d86e98295a..b091f2dd42 100644 --- a/examples/animation/custom_skinned_mesh.rs +++ b/examples/animation/custom_skinned_mesh.rs @@ -20,6 +20,10 @@ 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(); @@ -36,7 +40,6 @@ fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, - mut images: ResMut>, mut materials: ResMut>, mut skinned_mesh_inverse_bindposes_assets: ResMut>, ) { @@ -44,10 +47,6 @@ 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 5f414087fa..48f7cd6f39 100644 --- a/examples/animation/gltf_skinned_mesh.rs +++ b/examples/animation/gltf_skinned_mesh.rs @@ -8,24 +8,20 @@ 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, - mut images: ResMut>, -) { +fn setup(mut commands: Commands, asset_server: Res) { // 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 7c2c9a00ac..258059bf55 100644 --- a/examples/animation/morph_targets.rs +++ b/examples/animation/morph_targets.rs @@ -19,6 +19,10 @@ fn main() { }), ..default() })) + .insert_resource(AmbientLight { + brightness: 150.0, + ..default() + }) .add_systems(Startup, setup) .add_systems(Update, (name_morphs, setup_animations)) .run(); @@ -30,11 +34,7 @@ struct MorphData { mesh: Handle, } -fn setup( - asset_server: Res, - mut commands: Commands, - mut images: ResMut>, -) { +fn setup(asset_server: Res, mut commands: Commands) { commands.insert_resource(MorphData { the_wave: asset_server .load(GltfAssetLabel::Animation(2).from_asset("models/animated/MorphStressTest.gltf")), @@ -56,10 +56,6 @@ fn setup( 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 c4b4c92684..cc233eb5fd 100644 --- a/examples/asset/multi_asset_sync.rs +++ b/examples/asset/multi_asset_sync.rs @@ -17,6 +17,11 @@ 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) @@ -180,17 +185,12 @@ 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 26246faf79..56633977e6 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)) + app.add_systems(Startup, (setup_cameras, setup_lights, setup_ambient_light)) .add_systems( Update, ( @@ -292,21 +292,14 @@ const CIRCULAR_SEGMENT: CircularSegment = CircularSegment { }, }; -fn setup_cameras(mut commands: Commands, mut images: ResMut>) { +fn setup_cameras(mut commands: Commands) { let start_in_2d = true; let make_camera = |is_active| Camera { is_active, ..Default::default() }; - commands.spawn(( - Camera2d, - make_camera(start_in_2d), - EnvironmentMapLight { - intensity: 50.0, - ..EnvironmentMapLight::solid_color(&mut images, Color::WHITE) - }, - )); + commands.spawn((Camera2d, make_camera(start_in_2d))); commands.spawn(( Camera3d::default(), @@ -315,6 +308,10 @@ fn setup_cameras(mut commands: Commands, mut images: ResMut>) { )); } +fn setup_ambient_light(mut ambient_light: ResMut) { + ambient_light.brightness = 50.0; +} + fn setup_lights(mut commands: Commands) { commands.spawn(( PointLight {