diff --git a/_release-content/migration-guides/atmosphere_multicam.md b/_release-content/migration-guides/atmosphere_multicam.md new file mode 100644 index 0000000000000..2b5ca0085bf60 --- /dev/null +++ b/_release-content/migration-guides/atmosphere_multicam.md @@ -0,0 +1,10 @@ +--- +title: "Atmosphere now supports multiple cameras" +pull_requests: [23113] +--- + +Atmosphere now works correctly with multiple cameras. No action is required for most users. + +`init_atmosphere_buffer` has been removed, and `AtmosphereBuffer` has been changed from a `Resource` to a `Component` attached to each camera entity. + +If you were directly accessing `AtmosphereBuffer` as a resource in a render world system, you'll need to query for it as a component on camera entities instead. diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_pbr/src/atmosphere/mod.rs index ab0ed86263745..183c3e69132e5 100644 --- a/crates/bevy_pbr/src/atmosphere/mod.rs +++ b/crates/bevy_pbr/src/atmosphere/mod.rs @@ -85,7 +85,7 @@ use resources::{ }; use tracing::warn; -use crate::resources::{init_atmosphere_buffer, write_atmosphere_buffer}; +use crate::resources::prepare_atmosphere_buffers; use self::resources::{ prepare_atmosphere_bind_groups, prepare_atmosphere_textures, AtmosphereBindGroupLayouts, @@ -165,12 +165,7 @@ impl Plugin for AtmospherePlugin { .init_gpu_resource::>() .add_systems( RenderStartup, - ( - init_atmosphere_probe_layout, - init_atmosphere_probe_pipeline, - init_atmosphere_buffer, - ) - .chain(), + (init_atmosphere_probe_layout, init_atmosphere_probe_pipeline).chain(), ) .add_systems( Render, @@ -187,7 +182,7 @@ impl Plugin for AtmospherePlugin { prepare_atmosphere_probe_bind_groups.in_set(RenderSystems::PrepareBindGroups), prepare_atmosphere_transforms.in_set(RenderSystems::PrepareResources), prepare_atmosphere_bind_groups.in_set(RenderSystems::PrepareBindGroups), - write_atmosphere_buffer.in_set(RenderSystems::PrepareResources), + prepare_atmosphere_buffers.in_set(RenderSystems::PrepareResources), ), ) .add_systems( diff --git a/crates/bevy_pbr/src/atmosphere/resources.rs b/crates/bevy_pbr/src/atmosphere/resources.rs index e6cd09c83d720..6f77899ab1f98 100644 --- a/crates/bevy_pbr/src/atmosphere/resources.rs +++ b/crates/bevy_pbr/src/atmosphere/resources.rs @@ -792,32 +792,44 @@ pub(super) fn prepare_atmosphere_bind_groups( Ok(()) } -pub fn init_atmosphere_buffer(mut commands: Commands) { - commands.insert_resource(AtmosphereBuffer { - buffer: StorageBuffer::from(GpuAtmosphere { - ground_albedo: Vec3::ZERO, - inner_radius: 0.0, - outer_radius: 0.0, - world_to_atmosphere: Mat4::IDENTITY, - }), - }); +#[derive(ShaderType)] +#[repr(C)] +pub(crate) struct AtmosphereData { + pub atmosphere: GpuAtmosphere, + pub settings: GpuAtmosphereSettings, } -#[derive(Resource)] +#[derive(Component)] pub struct AtmosphereBuffer { - pub(crate) buffer: StorageBuffer, + pub(crate) buffer: StorageBuffer, } -pub(crate) fn write_atmosphere_buffer( +pub(crate) fn prepare_atmosphere_buffers( device: Res, queue: Res, - atmosphere_entity: Query<&GpuAtmosphere, With>, - mut atmosphere_buffer: ResMut, + mut views: Query< + ( + Entity, + &GpuAtmosphere, + &GpuAtmosphereSettings, + Option<&mut AtmosphereBuffer>, + ), + With, + >, + mut commands: Commands, ) { - let Ok(atmosphere) = atmosphere_entity.single() else { - return; - }; - - atmosphere_buffer.buffer.set(atmosphere.clone()); - atmosphere_buffer.buffer.write_buffer(&device, &queue); + for (entity, atmosphere, settings, existing_buffer) in &mut views { + let data = AtmosphereData { + atmosphere: atmosphere.clone(), + settings: settings.clone(), + }; + if let Some(mut atmosphere_buffer) = existing_buffer { + atmosphere_buffer.buffer.set(data); + atmosphere_buffer.buffer.write_buffer(&device, &queue); + } else { + let mut buffer = StorageBuffer::from(data); + buffer.write_buffer(&device, &queue); + commands.entity(entity).insert(AtmosphereBuffer { buffer }); + } + } } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 253540c6dbcb9..47d23d7fc8686 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1,6 +1,7 @@ use crate::contact_shadows::ViewContactShadowsUniformOffset; use crate::{ - material_bind_groups::MaterialBindGroupSlot, resources::write_atmosphere_buffer, + material_bind_groups::{MaterialBindGroupIndex, MaterialBindGroupSlot}, + resources::prepare_atmosphere_buffers, skin::skin_uniforms_from_world, }; use alloc::sync::Arc; @@ -215,7 +216,7 @@ impl Plugin for MeshRenderPlugin { prepare_mesh_view_bind_groups .in_set(RenderSystems::PrepareBindGroups) .after(prepare_oit_buffers) - .after(write_atmosphere_buffer), + .after(prepare_atmosphere_buffers), no_gpu_preprocessing::clear_batched_cpu_instance_buffers:: .in_set(RenderSystems::Cleanup) .after(RenderSystems::Render), diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index ecec2a56200c1..cd013fb234567 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -637,6 +637,7 @@ pub fn prepare_mesh_view_bind_groups( Option<&ViewPrepassTextures>, Option<&ViewTransmissionTexture>, Option<&AtmosphereTextures>, + Option<&AtmosphereBuffer>, &Tonemapping, ( Option<&RenderViewLightProbes>, @@ -668,18 +669,9 @@ pub fn prepare_mesh_view_bind_groups( Res, Res, ), - ( - decals_buffer, - render_decals, - atmosphere_buffer, - atmosphere_sampler, - blue_noise, - area_light_luts, - dfg_lut, - ): ( + (decals_buffer, render_decals, atmosphere_sampler, blue_noise, area_light_luts, dfg_lut): ( Res, Res, - Option>, Option>, Res, Res, @@ -719,6 +711,7 @@ pub fn prepare_mesh_view_bind_groups( prepass_textures, transmission_texture, atmosphere_textures, + atmosphere_buffer, tonemapping, (render_view_environment_maps, render_view_irradiance_volumes), has_atmosphere, @@ -826,7 +819,7 @@ pub fn prepare_mesh_view_bind_groups( if has_atmosphere && let Some(atmosphere_textures) = atmosphere_textures - && let Some(atmosphere_buffer) = atmosphere_buffer.as_ref() + && let Some(atmosphere_buffer) = atmosphere_buffer && let Some(atmosphere_sampler) = atmosphere_sampler.as_ref() && let Some(atmosphere_buffer_binding) = atmosphere_buffer.buffer.binding() {