1use crate::{
2 ExtractedAtmosphere, GpuLights, GpuScatteringMedium, LightMeta, ScatteringMediumSampler,
3};
4use bevy_asset::{load_embedded_asset, AssetId, Handle};
5use bevy_camera::{Camera, Camera3d};
6use bevy_core_pipeline::FullscreenShader;
7use bevy_derive::Deref;
8use bevy_ecs::{
9 component::Component,
10 entity::Entity,
11 error::BevyError,
12 query::With,
13 resource::Resource,
14 system::{Commands, Query, Res, ResMut},
15 world::{FromWorld, World},
16};
17use bevy_image::ToExtents;
18use bevy_light::atmosphere::ScatteringMedium;
19use bevy_math::{Affine3A, Mat4, Vec3, Vec3A};
20use bevy_render::{
21 extract_component::ComponentUniforms,
22 render_asset::RenderAssets,
23 render_resource::{binding_types::*, *},
24 renderer::{RenderDevice, RenderQueue},
25 texture::{CachedTexture, TextureCache},
26 view::{ExtractedView, Msaa, ViewDepthStencilTexture, ViewUniform, ViewUniforms},
27};
28use bevy_shader::Shader;
29use bevy_utils::default;
30
31use super::GpuAtmosphereSettings;
32
33#[derive(Resource)]
34pub(crate) struct AtmosphereBindGroupLayouts {
35 pub transmittance_lut: BindGroupLayoutDescriptor,
36 pub multiscattering_lut: BindGroupLayoutDescriptor,
37 pub sky_view_lut: BindGroupLayoutDescriptor,
38 pub aerial_view_lut: BindGroupLayoutDescriptor,
39}
40
41#[derive(Resource)]
42pub(crate) struct RenderSkyBindGroupLayouts {
43 pub render_sky: BindGroupLayoutDescriptor,
44 pub render_sky_msaa: BindGroupLayoutDescriptor,
45 pub fullscreen_shader: FullscreenShader,
46 pub fragment_shader: Handle<Shader>,
47}
48
49impl AtmosphereBindGroupLayouts {
50 pub fn new() -> Self {
51 let transmittance_lut = BindGroupLayoutDescriptor::new(
52 "transmittance_lut_bind_group_layout",
53 &BindGroupLayoutEntries::with_indices(
54 ShaderStages::COMPUTE,
55 (
56 (0, uniform_buffer::<GpuAtmosphere>(true)),
57 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
58 (5, texture_2d(TextureSampleType::default())),
60 (6, texture_2d(TextureSampleType::default())),
61 (7, sampler(SamplerBindingType::Filtering)),
62 (
64 13,
65 texture_storage_2d(
66 TextureFormat::Rgba16Float,
67 StorageTextureAccess::WriteOnly,
68 ),
69 ),
70 ),
71 ),
72 );
73
74 let multiscattering_lut = BindGroupLayoutDescriptor::new(
75 "multiscattering_lut_bind_group_layout",
76 &BindGroupLayoutEntries::with_indices(
77 ShaderStages::COMPUTE,
78 (
79 (0, uniform_buffer::<GpuAtmosphere>(true)),
80 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
81 (5, texture_2d(TextureSampleType::default())),
83 (6, texture_2d(TextureSampleType::default())),
84 (7, sampler(SamplerBindingType::Filtering)),
85 (8, texture_2d(TextureSampleType::default())), (12, sampler(SamplerBindingType::Filtering)),
88 (
90 13,
91 texture_storage_2d(
92 TextureFormat::Rgba16Float,
93 StorageTextureAccess::WriteOnly,
94 ),
95 ),
96 ),
97 ),
98 );
99
100 let sky_view_lut = BindGroupLayoutDescriptor::new(
101 "sky_view_lut_bind_group_layout",
102 &BindGroupLayoutEntries::with_indices(
103 ShaderStages::COMPUTE,
104 (
105 (0, uniform_buffer::<GpuAtmosphere>(true)),
106 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
107 (2, uniform_buffer::<AtmosphereTransform>(true)),
108 (3, uniform_buffer::<ViewUniform>(true)),
109 (4, uniform_buffer::<GpuLights>(true)),
110 (5, texture_2d(TextureSampleType::default())),
112 (6, texture_2d(TextureSampleType::default())),
113 (7, sampler(SamplerBindingType::Filtering)),
114 (8, texture_2d(TextureSampleType::default())), (9, texture_2d(TextureSampleType::default())), (12, sampler(SamplerBindingType::Filtering)),
118 (
120 13,
121 texture_storage_2d(
122 TextureFormat::Rgba16Float,
123 StorageTextureAccess::WriteOnly,
124 ),
125 ),
126 ),
127 ),
128 );
129
130 let aerial_view_lut = BindGroupLayoutDescriptor::new(
131 "aerial_view_lut_bind_group_layout",
132 &BindGroupLayoutEntries::with_indices(
133 ShaderStages::COMPUTE,
134 (
135 (0, uniform_buffer::<GpuAtmosphere>(true)),
136 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
137 (3, uniform_buffer::<ViewUniform>(true)),
138 (4, uniform_buffer::<GpuLights>(true)),
139 (5, texture_2d(TextureSampleType::default())),
141 (6, texture_2d(TextureSampleType::default())),
142 (7, sampler(SamplerBindingType::Filtering)),
143 (8, texture_2d(TextureSampleType::default())), (9, texture_2d(TextureSampleType::default())), (12, sampler(SamplerBindingType::Filtering)),
147 (
149 13,
150 texture_storage_3d(
151 TextureFormat::Rgba16Float,
152 StorageTextureAccess::WriteOnly,
153 ),
154 ),
155 ),
156 ),
157 );
158
159 Self {
160 transmittance_lut,
161 multiscattering_lut,
162 sky_view_lut,
163 aerial_view_lut,
164 }
165 }
166}
167
168impl FromWorld for RenderSkyBindGroupLayouts {
169 fn from_world(world: &mut World) -> Self {
170 let render_sky = BindGroupLayoutDescriptor::new(
171 "render_sky_bind_group_layout",
172 &BindGroupLayoutEntries::with_indices(
173 ShaderStages::FRAGMENT,
174 (
175 (0, uniform_buffer::<GpuAtmosphere>(true)),
176 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
177 (2, uniform_buffer::<AtmosphereTransform>(true)),
178 (3, uniform_buffer::<ViewUniform>(true)),
179 (4, uniform_buffer::<GpuLights>(true)),
180 (5, texture_2d(TextureSampleType::default())),
182 (6, texture_2d(TextureSampleType::default())),
183 (7, sampler(SamplerBindingType::Filtering)),
184 (8, texture_2d(TextureSampleType::default())), (9, texture_2d(TextureSampleType::default())), (10, texture_2d(TextureSampleType::default())), (11, texture_3d(TextureSampleType::default())), (12, sampler(SamplerBindingType::Filtering)),
190 (13, texture_2d(TextureSampleType::Depth)),
192 ),
193 ),
194 );
195
196 let render_sky_msaa = BindGroupLayoutDescriptor::new(
197 "render_sky_msaa_bind_group_layout",
198 &BindGroupLayoutEntries::with_indices(
199 ShaderStages::FRAGMENT,
200 (
201 (0, uniform_buffer::<GpuAtmosphere>(true)),
202 (1, uniform_buffer::<GpuAtmosphereSettings>(true)),
203 (2, uniform_buffer::<AtmosphereTransform>(true)),
204 (3, uniform_buffer::<ViewUniform>(true)),
205 (4, uniform_buffer::<GpuLights>(true)),
206 (5, texture_2d(TextureSampleType::default())),
208 (6, texture_2d(TextureSampleType::default())),
209 (7, sampler(SamplerBindingType::Filtering)),
210 (8, texture_2d(TextureSampleType::default())), (9, texture_2d(TextureSampleType::default())), (10, texture_2d(TextureSampleType::default())), (11, texture_3d(TextureSampleType::default())), (12, sampler(SamplerBindingType::Filtering)),
216 (13, texture_2d_multisampled(TextureSampleType::Depth)),
218 ),
219 ),
220 );
221
222 Self {
223 render_sky,
224 render_sky_msaa,
225 fullscreen_shader: world.resource::<FullscreenShader>().clone(),
226 fragment_shader: load_embedded_asset!(world, "render_sky.wesl"),
227 }
228 }
229}
230
231#[derive(Resource, Deref)]
232pub struct AtmosphereSampler(Sampler);
233
234impl FromWorld for AtmosphereSampler {
235 fn from_world(world: &mut World) -> Self {
236 let render_device = world.resource::<RenderDevice>();
237
238 let sampler = render_device.create_sampler(&SamplerDescriptor {
239 mag_filter: FilterMode::Linear,
240 min_filter: FilterMode::Linear,
241 mipmap_filter: MipmapFilterMode::Nearest,
242 ..Default::default()
243 });
244
245 Self(sampler)
246 }
247}
248
249#[derive(Resource)]
250pub(crate) struct AtmosphereLutPipelines {
251 pub transmittance_lut: CachedComputePipelineId,
252 pub multiscattering_lut: CachedComputePipelineId,
253 pub sky_view_lut: CachedComputePipelineId,
254 pub aerial_view_lut: CachedComputePipelineId,
255}
256
257impl FromWorld for AtmosphereLutPipelines {
258 fn from_world(world: &mut World) -> Self {
259 let pipeline_cache = world.resource::<PipelineCache>();
260 let layouts = world.resource::<AtmosphereBindGroupLayouts>();
261
262 let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
263 label: Some("transmittance_lut_pipeline".into()),
264 layout: vec![layouts.transmittance_lut.clone()],
265 shader: load_embedded_asset!(world, "transmittance_lut.wesl"),
266 ..default()
267 });
268
269 let multiscattering_lut =
270 pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
271 label: Some("multi_scattering_lut_pipeline".into()),
272 layout: vec![layouts.multiscattering_lut.clone()],
273 shader: load_embedded_asset!(world, "multiscattering_lut.wesl"),
274 ..default()
275 });
276
277 let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
278 label: Some("sky_view_lut_pipeline".into()),
279 layout: vec![layouts.sky_view_lut.clone()],
280 shader: load_embedded_asset!(world, "sky_view_lut.wesl"),
281 ..default()
282 });
283
284 let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
285 label: Some("aerial_view_lut_pipeline".into()),
286 layout: vec![layouts.aerial_view_lut.clone()],
287 shader: load_embedded_asset!(world, "aerial_view_lut.wesl"),
288 ..default()
289 });
290
291 Self {
292 transmittance_lut,
293 multiscattering_lut,
294 sky_view_lut,
295 aerial_view_lut,
296 }
297 }
298}
299
300#[derive(Component)]
301pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId);
302
303#[derive(Copy, Clone, Hash, PartialEq, Eq)]
304pub(crate) struct RenderSkyPipelineKey {
305 pub msaa_samples: u32,
306 pub dual_source_blending: bool,
307}
308
309impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts {
310 type Key = RenderSkyPipelineKey;
311
312 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
313 let mut shader_defs = Vec::new();
314
315 if key.msaa_samples > 1 {
316 shader_defs.push("MULTISAMPLED".into());
317 }
318 if key.dual_source_blending {
319 shader_defs.push("DUAL_SOURCE_BLENDING".into());
320 }
321
322 let dst_factor = if key.dual_source_blending {
323 BlendFactor::Src1
324 } else {
325 BlendFactor::SrcAlpha
326 };
327
328 RenderPipelineDescriptor {
329 label: Some(format!("render_sky_pipeline_{}", key.msaa_samples).into()),
330 layout: vec![if key.msaa_samples == 1 {
331 self.render_sky.clone()
332 } else {
333 self.render_sky_msaa.clone()
334 }],
335 vertex: self.fullscreen_shader.to_vertex_state(),
336 fragment: Some(FragmentState {
337 shader: self.fragment_shader.clone(),
338 shader_defs,
339 targets: vec![Some(ColorTargetState {
340 format: TextureFormat::Rgba16Float,
341 blend: Some(BlendState {
342 color: BlendComponent {
343 src_factor: BlendFactor::One,
344 dst_factor,
345 operation: BlendOperation::Add,
346 },
347 alpha: BlendComponent {
348 src_factor: BlendFactor::Zero,
349 dst_factor: BlendFactor::One,
350 operation: BlendOperation::Add,
351 },
352 }),
353 write_mask: ColorWrites::ALL,
354 })],
355 ..default()
356 }),
357 multisample: MultisampleState {
358 count: key.msaa_samples,
359 ..default()
360 },
361 ..default()
362 }
363 }
364}
365
366pub(super) fn queue_render_sky_pipelines(
367 views: Query<(Entity, &Msaa), (With<Camera>, With<ExtractedAtmosphere>)>,
368 pipeline_cache: Res<PipelineCache>,
369 layouts: Res<RenderSkyBindGroupLayouts>,
370 mut specializer: ResMut<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>,
371 render_device: Res<RenderDevice>,
372 mut commands: Commands,
373) {
374 for (entity, msaa) in &views {
375 let id = specializer.specialize(
376 &pipeline_cache,
377 &layouts,
378 RenderSkyPipelineKey {
379 msaa_samples: msaa.samples(),
380 dual_source_blending: render_device
381 .features()
382 .contains(WgpuFeatures::DUAL_SOURCE_BLENDING),
383 },
384 );
385 commands.entity(entity).insert(RenderSkyPipelineId(id));
386 }
387}
388
389#[derive(Component)]
390pub struct AtmosphereTextures {
391 pub transmittance_lut: CachedTexture,
392 pub multiscattering_lut: CachedTexture,
393 pub sky_view_lut: CachedTexture,
394 pub aerial_view_lut: CachedTexture,
395}
396
397pub(super) fn prepare_atmosphere_textures(
398 views: Query<(Entity, &GpuAtmosphereSettings), With<ExtractedAtmosphere>>,
399 render_device: Res<RenderDevice>,
400 mut texture_cache: ResMut<TextureCache>,
401 mut commands: Commands,
402) {
403 for (entity, lut_settings) in &views {
404 let transmittance_lut = texture_cache.get(
405 &render_device,
406 TextureDescriptor {
407 label: Some("transmittance_lut"),
408 size: lut_settings.transmittance_lut_size.to_extents(),
409 mip_level_count: 1,
410 sample_count: 1,
411 dimension: TextureDimension::D2,
412 format: TextureFormat::Rgba16Float,
413 usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
414 view_formats: &[],
415 },
416 );
417
418 let multiscattering_lut = texture_cache.get(
419 &render_device,
420 TextureDescriptor {
421 label: Some("multiscattering_lut"),
422 size: lut_settings.multiscattering_lut_size.to_extents(),
423 mip_level_count: 1,
424 sample_count: 1,
425 dimension: TextureDimension::D2,
426 format: TextureFormat::Rgba16Float,
427 usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
428 view_formats: &[],
429 },
430 );
431
432 let sky_view_lut = texture_cache.get(
433 &render_device,
434 TextureDescriptor {
435 label: Some("sky_view_lut"),
436 size: lut_settings.sky_view_lut_size.to_extents(),
437 mip_level_count: 1,
438 sample_count: 1,
439 dimension: TextureDimension::D2,
440 format: TextureFormat::Rgba16Float,
441 usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
442 view_formats: &[],
443 },
444 );
445
446 let aerial_view_lut = texture_cache.get(
447 &render_device,
448 TextureDescriptor {
449 label: Some("aerial_view_lut"),
450 size: lut_settings.aerial_view_lut_size.to_extents(),
451 mip_level_count: 1,
452 sample_count: 1,
453 dimension: TextureDimension::D3,
454 format: TextureFormat::Rgba16Float,
455 usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
456 view_formats: &[],
457 },
458 );
459
460 commands.entity(entity).insert({
461 AtmosphereTextures {
462 transmittance_lut,
463 multiscattering_lut,
464 sky_view_lut,
465 aerial_view_lut,
466 }
467 });
468 }
469}
470
471#[derive(Copy, Clone, Debug, thiserror::Error)]
472#[error("ScatteringMedium missing with id {0:?}: make sure the asset was not removed.")]
473struct ScatteringMediumMissingError(AssetId<ScatteringMedium>);
474
475#[derive(Clone, Component, ShaderType)]
477pub struct GpuAtmosphere {
478 pub ground_albedo: Vec3,
480 pub inner_radius: f32,
481 pub outer_radius: f32,
482 pub world_to_atmosphere: Mat4,
483}
484
485pub fn prepare_atmosphere_uniforms(
486 mut commands: Commands,
487 atmospheres: Query<(Entity, &ExtractedAtmosphere)>,
488) -> Result<(), BevyError> {
489 for (entity, atmosphere) in atmospheres {
490 commands.entity(entity).insert(GpuAtmosphere {
491 ground_albedo: atmosphere.ground_albedo,
492 inner_radius: atmosphere.inner_radius,
493 outer_radius: atmosphere.outer_radius,
494 world_to_atmosphere: atmosphere.world_to_atmosphere,
495 });
496 }
497 Ok(())
498}
499
500#[derive(Resource, Default)]
501pub struct AtmosphereTransforms {
502 uniforms: DynamicUniformBuffer<AtmosphereTransform>,
503}
504
505impl AtmosphereTransforms {
506 #[inline]
507 pub fn uniforms(&self) -> &DynamicUniformBuffer<AtmosphereTransform> {
508 &self.uniforms
509 }
510}
511
512#[derive(ShaderType)]
519pub struct AtmosphereTransform {
520 world_from_atmosphere: Mat4,
521 atmosphere_from_world: Mat4,
522}
523
524#[derive(Component)]
525pub struct AtmosphereTransformsOffset {
526 index: u32,
527}
528
529impl AtmosphereTransformsOffset {
530 #[inline]
531 pub fn index(&self) -> u32 {
532 self.index
533 }
534}
535
536pub(super) fn prepare_atmosphere_transforms(
537 views: Query<
538 (Entity, &ExtractedView, &GpuAtmosphere),
539 (With<ExtractedAtmosphere>, With<Camera3d>),
540 >,
541 render_device: Res<RenderDevice>,
542 render_queue: Res<RenderQueue>,
543 mut atmo_uniforms: ResMut<AtmosphereTransforms>,
544 mut commands: Commands,
545) {
546 let atmo_count = views.iter().len();
547 let Some(mut writer) =
548 atmo_uniforms
549 .uniforms
550 .get_writer(atmo_count, &render_device, &render_queue)
551 else {
552 return;
553 };
554
555 for (entity, view, gpu_atmosphere) in &views {
556 let cam_world = view.world_from_view.translation();
558 let cam_pos = Vec3A::from(
559 gpu_atmosphere
560 .world_to_atmosphere
561 .transform_point3(cam_world),
562 );
563
564 let atmo_y = cam_pos.try_normalize().unwrap_or(Vec3A::Y);
566
567 let world_ref = Vec3A::NEG_Z;
569 let ref_horizontal = world_ref - atmo_y * atmo_y.dot(world_ref);
570 let atmo_z = ref_horizontal.try_normalize().unwrap_or_else(|| {
571 let fallback_ref = Vec3A::NEG_Y;
573 (fallback_ref - atmo_y * atmo_y.dot(fallback_ref)).normalize()
574 });
575 let atmo_x = atmo_y.cross(atmo_z).normalize();
576
577 let world_from_atmosphere = Mat4::from(Affine3A::from_cols(
578 atmo_x,
579 atmo_y,
580 atmo_z,
581 view.world_from_view.translation_vec3a(),
582 ));
583 let atmosphere_from_world = world_from_atmosphere.transpose();
586
587 commands.entity(entity).insert(AtmosphereTransformsOffset {
588 index: writer.write(&AtmosphereTransform {
589 world_from_atmosphere,
590 atmosphere_from_world,
591 }),
592 });
593 }
594}
595
596#[derive(Component)]
597pub(crate) struct AtmosphereBindGroups {
598 pub transmittance_lut: BindGroup,
599 pub multiscattering_lut: BindGroup,
600 pub sky_view_lut: BindGroup,
601 pub aerial_view_lut: BindGroup,
602 pub render_sky: BindGroup,
603}
604
605#[derive(Copy, Clone, Debug, thiserror::Error)]
606enum AtmosphereBindGroupError {
607 #[error("Failed to prepare atmosphere bind groups. Atmosphere uniform buffer missing")]
608 Atmosphere,
609 #[error(
610 "Failed to prepare atmosphere bind groups. AtmosphereTransforms uniform buffer missing"
611 )]
612 Transforms,
613 #[error("Failed to prepare atmosphere bind groups. AtmosphereSettings uniform buffer missing")]
614 Settings,
615 #[error("Failed to prepare atmosphere bind groups. View uniform buffer missing")]
616 ViewUniforms,
617 #[error("Failed to prepare atmosphere bind groups. Light uniform buffer missing")]
618 LightUniforms,
619}
620
621pub(super) fn prepare_atmosphere_bind_groups(
622 views: Query<
623 (
624 Entity,
625 &ExtractedAtmosphere,
626 &AtmosphereTextures,
627 &ViewDepthStencilTexture,
628 &Msaa,
629 ),
630 (With<Camera3d>, With<ExtractedAtmosphere>),
631 >,
632 render_device: Res<RenderDevice>,
633 layouts: Res<AtmosphereBindGroupLayouts>,
634 render_sky_layouts: Res<RenderSkyBindGroupLayouts>,
635 atmosphere_sampler: Res<AtmosphereSampler>,
636 view_uniforms: Res<ViewUniforms>,
637 lights_uniforms: Res<LightMeta>,
638 atmosphere_transforms: Res<AtmosphereTransforms>,
639 atmosphere_uniforms: Res<ComponentUniforms<GpuAtmosphere>>,
640 settings_uniforms: Res<ComponentUniforms<GpuAtmosphereSettings>>,
641 gpu_media: Res<RenderAssets<GpuScatteringMedium>>,
642 medium_sampler: Res<ScatteringMediumSampler>,
643 pipeline_cache: Res<PipelineCache>,
644 mut commands: Commands,
645) -> Result<(), BevyError> {
646 if views.iter().len() == 0 {
647 return Ok(());
648 }
649
650 let atmosphere_binding = atmosphere_uniforms
651 .binding()
652 .ok_or(AtmosphereBindGroupError::Atmosphere)?;
653
654 let transforms_binding = atmosphere_transforms
655 .uniforms()
656 .binding()
657 .ok_or(AtmosphereBindGroupError::Transforms)?;
658
659 let settings_binding = settings_uniforms
660 .binding()
661 .ok_or(AtmosphereBindGroupError::Settings)?;
662
663 let view_binding = view_uniforms
664 .uniforms
665 .binding()
666 .ok_or(AtmosphereBindGroupError::ViewUniforms)?;
667
668 let lights_binding = lights_uniforms
669 .view_gpu_lights
670 .binding()
671 .ok_or(AtmosphereBindGroupError::LightUniforms)?;
672
673 for (entity, atmosphere, textures, view_depth_texture, msaa) in &views {
674 let Some(depth_view) = view_depth_texture
675 .attachment
676 .depth_stencil_views()
677 .depth_only_view()
678 else {
679 continue;
680 };
681 let gpu_medium = gpu_media
682 .get(atmosphere.medium)
683 .ok_or(ScatteringMediumMissingError(atmosphere.medium))?;
684
685 let transmittance_lut = render_device.create_bind_group(
686 "transmittance_lut_bind_group",
687 &pipeline_cache.get_bind_group_layout(&layouts.transmittance_lut),
688 &BindGroupEntries::with_indices((
689 (0, atmosphere_binding.clone()),
691 (1, settings_binding.clone()),
692 (5, &gpu_medium.density_lut_view),
694 (6, &gpu_medium.scattering_lut_view),
695 (7, medium_sampler.sampler()),
696 (13, &textures.transmittance_lut.default_view),
698 )),
699 );
700
701 let multiscattering_lut = render_device.create_bind_group(
702 "multiscattering_lut_bind_group",
703 &pipeline_cache.get_bind_group_layout(&layouts.multiscattering_lut),
704 &BindGroupEntries::with_indices((
705 (0, atmosphere_binding.clone()),
707 (1, settings_binding.clone()),
708 (5, &gpu_medium.density_lut_view),
710 (6, &gpu_medium.scattering_lut_view),
711 (7, medium_sampler.sampler()),
712 (8, &textures.transmittance_lut.default_view),
714 (12, &**atmosphere_sampler),
715 (13, &textures.multiscattering_lut.default_view),
717 )),
718 );
719
720 let sky_view_lut = render_device.create_bind_group(
721 "sky_view_lut_bind_group",
722 &pipeline_cache.get_bind_group_layout(&layouts.sky_view_lut),
723 &BindGroupEntries::with_indices((
724 (0, atmosphere_binding.clone()),
726 (1, settings_binding.clone()),
727 (2, transforms_binding.clone()),
728 (3, view_binding.clone()),
729 (4, lights_binding.clone()),
730 (5, &gpu_medium.density_lut_view),
732 (6, &gpu_medium.scattering_lut_view),
733 (7, medium_sampler.sampler()),
734 (8, &textures.transmittance_lut.default_view),
736 (9, &textures.multiscattering_lut.default_view),
737 (12, &**atmosphere_sampler),
738 (13, &textures.sky_view_lut.default_view),
740 )),
741 );
742
743 let aerial_view_lut = render_device.create_bind_group(
744 "sky_view_lut_bind_group",
745 &pipeline_cache.get_bind_group_layout(&layouts.aerial_view_lut),
746 &BindGroupEntries::with_indices((
747 (0, atmosphere_binding.clone()),
749 (1, settings_binding.clone()),
750 (3, view_binding.clone()),
751 (4, lights_binding.clone()),
752 (5, &gpu_medium.density_lut_view),
754 (6, &gpu_medium.scattering_lut_view),
755 (7, medium_sampler.sampler()),
756 (8, &textures.transmittance_lut.default_view),
758 (9, &textures.multiscattering_lut.default_view),
759 (12, &**atmosphere_sampler),
760 (13, &textures.aerial_view_lut.default_view),
762 )),
763 );
764
765 let render_sky = render_device.create_bind_group(
766 "render_sky_bind_group",
767 &pipeline_cache.get_bind_group_layout(if *msaa == Msaa::Off {
768 &render_sky_layouts.render_sky
769 } else {
770 &render_sky_layouts.render_sky_msaa
771 }),
772 &BindGroupEntries::with_indices((
773 (0, atmosphere_binding.clone()),
775 (1, settings_binding.clone()),
776 (2, transforms_binding.clone()),
777 (3, view_binding.clone()),
778 (4, lights_binding.clone()),
779 (5, &gpu_medium.density_lut_view),
781 (6, &gpu_medium.scattering_lut_view),
782 (7, medium_sampler.sampler()),
783 (8, &textures.transmittance_lut.default_view),
785 (9, &textures.multiscattering_lut.default_view),
786 (10, &textures.sky_view_lut.default_view),
787 (11, &textures.aerial_view_lut.default_view),
788 (12, &**atmosphere_sampler),
789 (13, depth_view),
791 )),
792 );
793
794 commands.entity(entity).insert(AtmosphereBindGroups {
795 transmittance_lut,
796 multiscattering_lut,
797 sky_view_lut,
798 aerial_view_lut,
799 render_sky,
800 });
801 }
802
803 Ok(())
804}
805
806#[derive(ShaderType)]
807#[repr(C)]
808pub(crate) struct AtmosphereData {
809 pub atmosphere: GpuAtmosphere,
810 pub settings: GpuAtmosphereSettings,
811}
812
813#[derive(Component)]
814pub struct AtmosphereBuffer {
815 pub(crate) buffer: StorageBuffer<AtmosphereData>,
816}
817
818pub(crate) fn prepare_atmosphere_buffers(
819 device: Res<RenderDevice>,
820 queue: Res<RenderQueue>,
821 mut views: Query<
822 (
823 Entity,
824 &GpuAtmosphere,
825 &GpuAtmosphereSettings,
826 Option<&mut AtmosphereBuffer>,
827 ),
828 With<ExtractedAtmosphere>,
829 >,
830 mut commands: Commands,
831) {
832 for (entity, atmosphere, settings, existing_buffer) in &mut views {
833 let data = AtmosphereData {
834 atmosphere: atmosphere.clone(),
835 settings: settings.clone(),
836 };
837 if let Some(mut atmosphere_buffer) = existing_buffer {
838 atmosphere_buffer.buffer.set(data);
839 atmosphere_buffer.buffer.write_buffer(&device, &queue);
840 } else {
841 let mut buffer = StorageBuffer::from(data);
842 buffer.write_buffer(&device, &queue);
843 commands.entity(entity).insert(AtmosphereBuffer { buffer });
844 }
845 }
846}