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<Image>,
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.
This commit is contained in:
Shaye Garg 2025-03-04 01:40:53 -06:00 committed by GitHub
parent 0a841ba9c1
commit 0b5302d96a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 348 additions and 212 deletions

View File

@ -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<Shader> =
weak_handle!("9afeaeab-7c45-43ce-b322-4b97799eaeb9");
pub const PBR_FUNCTIONS_HANDLE: Handle<Shader> =
weak_handle!("815b8618-f557-4a96-91a5-a2fb7e249fb0");
pub const PBR_AMBIENT_HANDLE: Handle<Shader> = weak_handle!("4a90b95b-112a-4a10-9145-7590d6f14260");
pub const PARALLAX_MAPPING_SHADER_HANDLE: Handle<Shader> =
weak_handle!("6cf57d9f-222a-429a-bba4-55ba9586e1d4");
pub const VIEW_TRANSFORMATIONS_SHADER_HANDLE: Handle<Shader> =
@ -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::<StandardMaterial>()
.register_type::<AmbientLight>()
.register_type::<CascadeShadowConfig>()
@ -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),

View File

@ -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.

View File

@ -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<Assets<Image>>,
ambient_light: Res<AmbientLight>,
new_views: Query<
(Entity, Option<Ref<AmbientLight>>),
(
With<Camera>,
Without<EnvironmentMapLight>,
Without<EnvironmentMapLightFromAmbientLight>,
),
>,
mut managed_views: Query<
(&mut EnvironmentMapLight, Option<Ref<AmbientLight>>),
With<EnvironmentMapLightFromAmbientLight>,
>,
) {
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<
(

View File

@ -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<Image>, 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<Image>,
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 {

View File

@ -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<f32>(cluster_dimensions.xy) / vec2<f32>(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<NoIndirectDrawing>,
Option<&AmbientLight>,
),
With<Camera3d>,
>,
ambient_light: Res<AmbientLight>,
point_light_shadow_map: Res<PointLightShadowMap>,
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
mut shadow_render_phases: ResMut<ViewBinnedRenderPhases<Shadow>>,
@ -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

View File

@ -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<DirectionalLight, #{MAX_DIRECTIONAL_LIGHTS}u>,
ambient_color: vec4<f32>,
// x/y/z dimensions and n_clusters in w
cluster_dimensions: vec4<u32>,
// xy are vec2<f32>(cluster_dimensions.xy) / vec2<f32>(view.width, view.height)

View File

@ -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<f32>,
world_normal: vec3<f32>,
V: vec3<f32>,
NdotV: f32,
diffuse_color: vec3<f32>,
specular_color: vec3<f32>,
perceptual_roughness: f32,
occlusion: vec3<f32>,
) -> vec3<f32> {
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;
}

View File

@ -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<f32>(0.0)
// diffuse_occlusion = vec3<f32>(1.0)
transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3<f32>(0.0), 1.0, vec3<f32>(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<f32>(0.0);

View File

@ -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<AssetServer>,
mut materials: ResMut<Assets<CustomMaterial>>,
mut images: ResMut<Assets<Image>>,
) {
// 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

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -157,11 +157,6 @@ fn main() {
.add_plugins(MaterialPlugin::<VoxelVisualizationMaterial>::default())
.init_resource::<AppStatus>()
.init_resource::<ExampleAssets>()
.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<ExampleAssets>, app_status: Res<AppStatus>) {
fn setup(
mut commands: Commands,
images: ResMut<Assets<Image>>,
assets: Res<ExampleAssets>,
app_status: Res<AppStatus>,
) {
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<Image>>,
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<Entity, With<LightProbe>>,
mut app_status: ResMut<AppStatus>,
assets: Res<ExampleAssets>,
mut ambient_light: ResMut<AmbientLight>,
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::<IrradianceVolume>();
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;
}
}

View File

@ -35,6 +35,7 @@ fn setup(
parameters: Res<Parameters>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>,
) {
@ -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())
},
));
}

View File

@ -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);

View File

@ -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::<AppStatus>()
.add_event::<WidgetClickEvent<LightingMode>>()
.add_event::<LightingModeChanged>()
@ -145,18 +140,28 @@ fn main() {
}
/// Creates the scene.
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_status: Res<AppStatus>) {
spawn_camera(&mut commands);
fn setup(
mut commands: Commands,
images: ResMut<Assets<Image>>,
asset_server: Res<AssetServer>,
app_status: Res<AppStatus>,
) {
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<Assets<Image>>) {
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.

View File

@ -17,7 +17,7 @@ fn main() {
.run();
}
fn setup_camera(mut commands: Commands) {
fn setup_camera(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
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<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.insert_resource(AmbientLight {
color: Color::WHITE,
brightness: 300.0,
..default()
});
commands.insert_resource(CameraMode::Chase);
commands.spawn((
DirectionalLight {

View File

@ -57,7 +57,11 @@ struct Cubemap {
image_handle: Handle<Image>,
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut images: ResMut<Assets<Image>>,
) {
// directional 'sun' light
commands.spawn((
DirectionalLight {
@ -78,17 +82,15 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
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,

View File

@ -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::<AppAssets>()
.init_resource::<AppStatus>()
.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())

View File

@ -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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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

View File

@ -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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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((

View File

@ -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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
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 {

View File

@ -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));

View File

@ -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 {

View File

@ -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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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

View File

@ -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<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut graphs: ResMut<Assets<AnimationGraph>>,
) {
@ -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

View File

@ -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::<ParticleAssets>()
.init_resource::<FoxFeetTargets>()
@ -78,6 +73,7 @@ fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut graphs: ResMut<Assets<AnimationGraph>>,
) {
@ -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

View File

@ -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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut animations: ResMut<Assets<AnimationClip>>,
mut graphs: ResMut<Assets<AnimationGraph>>,
@ -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

View File

@ -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<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
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((

View File

@ -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::<AppState>()
.run();
}
@ -120,12 +115,17 @@ fn setup_scene(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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.

View File

@ -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<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut skinned_mesh_inverse_bindposes_assets: ResMut<Assets<SkinnedMeshInverseBindposes>>,
) {
@ -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

View File

@ -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<AssetServer>) {
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut images: ResMut<Assets<Image>>,
) {
// 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`

View File

@ -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<Mesh>,
}
fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
fn setup(
asset_server: Res<AssetServer>,
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
) {
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<AssetServer>, 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)
},
));
}

View File

@ -17,11 +17,6 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_state::<LoadingState>()
.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<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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

View File

@ -14,7 +14,7 @@ fn main() {
.init_state::<CameraActive>();
// 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<Assets<Image>>) {
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<AmbientLight>) {
ambient_light.brightness = 50.0;
}
fn setup_lights(mut commands: Commands) {
commands.spawn((
PointLight {