From 0a4b9070e833cfa528652612481d0a3e2fe17c3d Mon Sep 17 00:00:00 2001 From: Dylan Sechet Date: Wed, 3 Jun 2026 14:55:52 +0200 Subject: [PATCH 1/3] feat: add toggle to regenerate GeneratedEnvironmentMapLight --- crates/bevy_light/src/probe.rs | 7 +++ crates/bevy_pbr/src/atmosphere/environment.rs | 1 + crates/bevy_pbr/src/light_probe/generate.rs | 59 +++++++++++++------ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/crates/bevy_light/src/probe.rs b/crates/bevy_light/src/probe.rs index b5ba960c99076..cdca3806c99d0 100644 --- a/crates/bevy_light/src/probe.rs +++ b/crates/bevy_light/src/probe.rs @@ -274,6 +274,12 @@ pub struct GeneratedEnvironmentMapLight { /// Whether this light contributes diffuse lighting to meshes that already /// have baked lightmaps. pub affects_lightmapped_mesh_diffuse: bool, + + /// Whether to re-filter the environment map. + /// + /// After setting this to true, it will automatically be toggled + /// back to false at the end of the frame. + pub regenerate: bool, } impl Default for GeneratedEnvironmentMapLight { @@ -283,6 +289,7 @@ impl Default for GeneratedEnvironmentMapLight { intensity: 0.0, rotation: Quat::IDENTITY, affects_lightmapped_mesh_diffuse: true, + regenerate: true, } } } diff --git a/crates/bevy_pbr/src/atmosphere/environment.rs b/crates/bevy_pbr/src/atmosphere/environment.rs index e19f39e15323b..6e595db8b53d9 100644 --- a/crates/bevy_pbr/src/atmosphere/environment.rs +++ b/crates/bevy_pbr/src/atmosphere/environment.rs @@ -239,6 +239,7 @@ pub fn prepare_atmosphere_probe_components( intensity: env_map_light.intensity, rotation: Quat::IDENTITY, affects_lightmapped_mesh_diffuse: env_map_light.affects_lightmapped_mesh_diffuse, + regenerate: true, }); } } diff --git a/crates/bevy_pbr/src/light_probe/generate.rs b/crates/bevy_pbr/src/light_probe/generate.rs index dc99a9688a97e..12346bf334140 100644 --- a/crates/bevy_pbr/src/light_probe/generate.rs +++ b/crates/bevy_pbr/src/light_probe/generate.rs @@ -17,7 +17,7 @@ use bevy_core_pipeline::mip_generation::{self, DownsampleShaders, DownsamplingCo use bevy_ecs::{ component::Component, entity::Entity, - query::Without, + query::{With, Without}, resource::Resource, schedule::IntoScheduleConfigs, system::{Commands, Query, Res, ResMut}, @@ -41,7 +41,7 @@ use bevy_render::{ sync_component::{SyncComponent, SyncComponentPlugin}, sync_world::RenderEntity, texture::{CachedTexture, GpuImage, TextureCache}, - Extract, ExtractSchedule, Render, RenderApp, RenderStartup, RenderSystems, + ExtractSchedule, MainWorld, Render, RenderApp, RenderStartup, RenderSystems, }; // Implementation: generate diffuse and specular cubemaps required by PBR @@ -433,17 +433,17 @@ pub fn initialize_generated_environment_map_resources( } pub fn extract_generated_environment_map_entities( - query: Extract< - Query<( - RenderEntity, - &GeneratedEnvironmentMapLight, - &EnvironmentMapLight, - )>, - >, mut commands: Commands, + mut main_world: ResMut, render_images: Res>, ) { - for (entity, filtered_env_map, env_map_light) in query.iter() { + let mut query = main_world.query::<( + RenderEntity, + &mut GeneratedEnvironmentMapLight, + &EnvironmentMapLight, + )>(); + + for (entity, mut filtered_env_map, env_map_light) in query.iter_mut(&mut main_world) { let Some(env_map) = render_images.get(&filtered_env_map.environment_map) else { continue; }; @@ -467,10 +467,16 @@ pub fn extract_generated_environment_map_entities( rotation: filtered_env_map.rotation, affects_lightmapped_mesh_diffuse: filtered_env_map.affects_lightmapped_mesh_diffuse, }; - commands + + let mut entity_commands = commands .get_entity(entity) - .expect("Entity not synced to render world") - .insert(render_filtered_env_map); + .expect("Entity not synced to render world"); + entity_commands.insert(render_filtered_env_map); + + if filtered_env_map.regenerate { + entity_commands.insert(RegenerateEnvironmentMap); + filtered_env_map.regenerate = false; + } } } @@ -485,6 +491,13 @@ pub struct RenderEnvironmentMap { pub affects_lightmapped_mesh_diffuse: bool, } +/// Marks a `RenderEnvironmentMap` as needing (re)generation. +/// +/// Persists until `filtering_system` has run, so the work gets +/// retried across frames if pipelines or assets aren't ready yet. +#[derive(Component)] +pub struct RegenerateEnvironmentMap; + #[derive(Component)] pub struct IntermediateTextures { pub environment_map: CachedTexture, @@ -500,7 +513,7 @@ fn compute_mip_count(size: u32) -> u32 { /// Prepares textures needed for single pass downsampling pub fn prepare_generated_environment_map_intermediate_textures( - light_probes: Query<(Entity, &RenderEnvironmentMap)>, + light_probes: Query<(Entity, &RenderEnvironmentMap), With>, render_device: Res, mut texture_cache: ResMut, mut commands: Commands, @@ -557,7 +570,10 @@ pub struct GeneratorBindGroups { /// Prepares bind groups for environment map generation pipelines pub fn prepare_generated_environment_map_bind_groups( - light_probes: Query<(Entity, &IntermediateTextures, &RenderEnvironmentMap)>, + light_probes: Query< + (Entity, &IntermediateTextures, &RenderEnvironmentMap), + With, + >, render_device: Res, pipeline_cache: Res, queue: Res, @@ -840,7 +856,7 @@ fn create_placeholder_storage_view(render_device: &RenderDevice) -> TextureView } pub fn downsampling_system( - query: Query<(&GeneratorBindGroups, &RenderEnvironmentMap)>, + query: Query<(&GeneratorBindGroups, &RenderEnvironmentMap), With>, pipeline_cache: Res, pipelines: Option>, mut ctx: RenderContext, @@ -940,9 +956,13 @@ pub fn downsampling_system( } pub fn filtering_system( - query: Query<(&GeneratorBindGroups, &RenderEnvironmentMap)>, + query: Query< + (Entity, &GeneratorBindGroups, &RenderEnvironmentMap), + With, + >, pipeline_cache: Res, pipelines: Option>, + mut commands: Commands, mut ctx: RenderContext, ) { let Some(pipelines) = pipelines else { @@ -960,7 +980,7 @@ pub fn filtering_system( let diagnostics = ctx.diagnostic_recorder(); let diagnostics = diagnostics.as_deref(); - for (bind_groups, env_map_light) in &query { + for (entity, bind_groups, env_map_light) in &query { // Radiance convolution pass { let mut compute_pass = @@ -1011,6 +1031,9 @@ pub fn filtering_system( irr_span.end(&mut compute_pass); } + + // The filtering has run, clear the marker. + commands.entity(entity).remove::(); } } From db16c3305ef124f3fe2721e0ca71349f3ec74f9d Mon Sep 17 00:00:00 2001 From: Dylan Sechet Date: Wed, 3 Jun 2026 15:29:23 +0200 Subject: [PATCH 2/3] fix: regenerate AtmosphereEnvironmentMap every frame --- crates/bevy_pbr/src/atmosphere/environment.rs | 8 ++++++++ crates/bevy_pbr/src/atmosphere/mod.rs | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/bevy_pbr/src/atmosphere/environment.rs b/crates/bevy_pbr/src/atmosphere/environment.rs index 6e595db8b53d9..cfe48c045af88 100644 --- a/crates/bevy_pbr/src/atmosphere/environment.rs +++ b/crates/bevy_pbr/src/atmosphere/environment.rs @@ -195,6 +195,14 @@ pub fn validate_environment_map_size(size: UVec2) -> UVec2 { new_size } +pub fn request_atmosphere_environment_map_regeneration( + mut probes: Query<&mut GeneratedEnvironmentMapLight, With>, +) { + for mut env_map in &mut probes { + env_map.regenerate = true; + } +} + pub fn prepare_atmosphere_probe_components( probes: Query<(Entity, &AtmosphereEnvironmentMapLight), (Without,)>, mut commands: Commands, diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index 183c3e69132e5..205813f687787 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -76,7 +76,8 @@ use bevy_shader::load_shader_library; use environment::{ atmosphere_environment, init_atmosphere_probe_layout, init_atmosphere_probe_pipeline, prepare_atmosphere_probe_bind_groups, prepare_atmosphere_probe_components, - prepare_probe_textures, AtmosphereEnvironmentMap, + prepare_probe_textures, request_atmosphere_environment_map_regeneration, + AtmosphereEnvironmentMap, }; use node::{atmosphere_luts, render_sky}; use resources::{ @@ -115,7 +116,13 @@ impl Plugin for AtmospherePlugin { UniformComponentPlugin::::default(), UniformComponentPlugin::::default(), )) - .add_systems(Update, prepare_atmosphere_probe_components); + .add_systems( + Update, + ( + prepare_atmosphere_probe_components, + request_atmosphere_environment_map_regeneration, + ), + ); if let Some(render_app) = app.get_sub_app_mut(RenderApp) { render_app.add_systems(ExtractSchedule, extract_atmosphere); From f9cc219de131bfec8111bd142ae5e294aad431cf Mon Sep 17 00:00:00 2001 From: Dylan Sechet Date: Wed, 3 Jun 2026 20:11:19 +0200 Subject: [PATCH 3/3] fix: ambiguity --- crates/bevy_pbr/src/atmosphere/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index 205813f687787..4d9aaf9bb935a 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -120,7 +120,8 @@ impl Plugin for AtmospherePlugin { Update, ( prepare_atmosphere_probe_components, - request_atmosphere_environment_map_regeneration, + request_atmosphere_environment_map_regeneration + .ambiguous_with(crate::light_probe::generate::generate_environment_map_light), ), );