bevy_pbr/atmosphere/
resources.rs

1use bevy_core_pipeline::{
2    core_3d::Camera3d, fullscreen_vertex_shader::fullscreen_shader_vertex_state,
3};
4use bevy_ecs::{
5    component::Component,
6    entity::Entity,
7    query::With,
8    resource::Resource,
9    system::{Commands, Query, Res, ResMut},
10    world::{FromWorld, World},
11};
12use bevy_math::{Mat4, Vec3};
13use bevy_render::{
14    camera::Camera,
15    extract_component::ComponentUniforms,
16    render_resource::{binding_types::*, *},
17    renderer::{RenderDevice, RenderQueue},
18    texture::{CachedTexture, TextureCache},
19    view::{ExtractedView, Msaa, ViewDepthTexture, ViewUniform, ViewUniforms},
20};
21
22use crate::{GpuLights, LightMeta};
23
24use super::{shaders, Atmosphere, AtmosphereSettings};
25
26#[derive(Resource)]
27pub(crate) struct AtmosphereBindGroupLayouts {
28    pub transmittance_lut: BindGroupLayout,
29    pub multiscattering_lut: BindGroupLayout,
30    pub sky_view_lut: BindGroupLayout,
31    pub aerial_view_lut: BindGroupLayout,
32}
33
34#[derive(Resource)]
35pub(crate) struct RenderSkyBindGroupLayouts {
36    pub render_sky: BindGroupLayout,
37    pub render_sky_msaa: BindGroupLayout,
38}
39
40impl FromWorld for AtmosphereBindGroupLayouts {
41    fn from_world(world: &mut World) -> Self {
42        let render_device = world.resource::<RenderDevice>();
43        let transmittance_lut = render_device.create_bind_group_layout(
44            "transmittance_lut_bind_group_layout",
45            &BindGroupLayoutEntries::with_indices(
46                ShaderStages::COMPUTE,
47                (
48                    (0, uniform_buffer::<Atmosphere>(true)),
49                    (1, uniform_buffer::<AtmosphereSettings>(true)),
50                    (
51                        // transmittance lut storage texture
52                        13,
53                        texture_storage_2d(
54                            TextureFormat::Rgba16Float,
55                            StorageTextureAccess::WriteOnly,
56                        ),
57                    ),
58                ),
59            ),
60        );
61
62        let multiscattering_lut = render_device.create_bind_group_layout(
63            "multiscattering_lut_bind_group_layout",
64            &BindGroupLayoutEntries::with_indices(
65                ShaderStages::COMPUTE,
66                (
67                    (0, uniform_buffer::<Atmosphere>(true)),
68                    (1, uniform_buffer::<AtmosphereSettings>(true)),
69                    (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
70                    (6, sampler(SamplerBindingType::Filtering)),
71                    (
72                        //multiscattering lut storage texture
73                        13,
74                        texture_storage_2d(
75                            TextureFormat::Rgba16Float,
76                            StorageTextureAccess::WriteOnly,
77                        ),
78                    ),
79                ),
80            ),
81        );
82
83        let sky_view_lut = render_device.create_bind_group_layout(
84            "sky_view_lut_bind_group_layout",
85            &BindGroupLayoutEntries::with_indices(
86                ShaderStages::COMPUTE,
87                (
88                    (0, uniform_buffer::<Atmosphere>(true)),
89                    (1, uniform_buffer::<AtmosphereSettings>(true)),
90                    (2, uniform_buffer::<AtmosphereTransform>(true)),
91                    (3, uniform_buffer::<ViewUniform>(true)),
92                    (4, uniform_buffer::<GpuLights>(true)),
93                    (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
94                    (6, sampler(SamplerBindingType::Filtering)),
95                    (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
96                    (8, sampler(SamplerBindingType::Filtering)),
97                    (
98                        13,
99                        texture_storage_2d(
100                            TextureFormat::Rgba16Float,
101                            StorageTextureAccess::WriteOnly,
102                        ),
103                    ),
104                ),
105            ),
106        );
107
108        let aerial_view_lut = render_device.create_bind_group_layout(
109            "aerial_view_lut_bind_group_layout",
110            &BindGroupLayoutEntries::with_indices(
111                ShaderStages::COMPUTE,
112                (
113                    (0, uniform_buffer::<Atmosphere>(true)),
114                    (1, uniform_buffer::<AtmosphereSettings>(true)),
115                    (3, uniform_buffer::<ViewUniform>(true)),
116                    (4, uniform_buffer::<GpuLights>(true)),
117                    (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
118                    (6, sampler(SamplerBindingType::Filtering)),
119                    (7, texture_2d(TextureSampleType::Float { filterable: true })), //multiscattering lut and sampler
120                    (8, sampler(SamplerBindingType::Filtering)),
121                    (
122                        //Aerial view lut storage texture
123                        13,
124                        texture_storage_3d(
125                            TextureFormat::Rgba16Float,
126                            StorageTextureAccess::WriteOnly,
127                        ),
128                    ),
129                ),
130            ),
131        );
132
133        Self {
134            transmittance_lut,
135            multiscattering_lut,
136            sky_view_lut,
137            aerial_view_lut,
138        }
139    }
140}
141
142impl FromWorld for RenderSkyBindGroupLayouts {
143    fn from_world(world: &mut World) -> Self {
144        let render_device = world.resource::<RenderDevice>();
145        let render_sky = render_device.create_bind_group_layout(
146            "render_sky_bind_group_layout",
147            &BindGroupLayoutEntries::with_indices(
148                ShaderStages::FRAGMENT,
149                (
150                    (0, uniform_buffer::<Atmosphere>(true)),
151                    (1, uniform_buffer::<AtmosphereSettings>(true)),
152                    (2, uniform_buffer::<AtmosphereTransform>(true)),
153                    (3, uniform_buffer::<ViewUniform>(true)),
154                    (4, uniform_buffer::<GpuLights>(true)),
155                    (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
156                    (6, sampler(SamplerBindingType::Filtering)),
157                    (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler
158                    (10, sampler(SamplerBindingType::Filtering)),
159                    (
160                        // aerial view lut and sampler
161                        11,
162                        texture_3d(TextureSampleType::Float { filterable: true }),
163                    ),
164                    (12, sampler(SamplerBindingType::Filtering)),
165                    (
166                        //view depth texture
167                        13,
168                        texture_2d(TextureSampleType::Depth),
169                    ),
170                ),
171            ),
172        );
173
174        let render_sky_msaa = render_device.create_bind_group_layout(
175            "render_sky_msaa_bind_group_layout",
176            &BindGroupLayoutEntries::with_indices(
177                ShaderStages::FRAGMENT,
178                (
179                    (0, uniform_buffer::<Atmosphere>(true)),
180                    (1, uniform_buffer::<AtmosphereSettings>(true)),
181                    (2, uniform_buffer::<AtmosphereTransform>(true)),
182                    (3, uniform_buffer::<ViewUniform>(true)),
183                    (4, uniform_buffer::<GpuLights>(true)),
184                    (5, texture_2d(TextureSampleType::Float { filterable: true })), //transmittance lut and sampler
185                    (6, sampler(SamplerBindingType::Filtering)),
186                    (9, texture_2d(TextureSampleType::Float { filterable: true })), //sky view lut and sampler
187                    (10, sampler(SamplerBindingType::Filtering)),
188                    (
189                        // aerial view lut and sampler
190                        11,
191                        texture_3d(TextureSampleType::Float { filterable: true }),
192                    ),
193                    (12, sampler(SamplerBindingType::Filtering)),
194                    (
195                        //view depth texture
196                        13,
197                        texture_2d_multisampled(TextureSampleType::Depth),
198                    ),
199                ),
200            ),
201        );
202
203        Self {
204            render_sky,
205            render_sky_msaa,
206        }
207    }
208}
209
210#[derive(Resource)]
211pub struct AtmosphereSamplers {
212    pub transmittance_lut: Sampler,
213    pub multiscattering_lut: Sampler,
214    pub sky_view_lut: Sampler,
215    pub aerial_view_lut: Sampler,
216}
217
218impl FromWorld for AtmosphereSamplers {
219    fn from_world(world: &mut World) -> Self {
220        let render_device = world.resource::<RenderDevice>();
221
222        let base_sampler = SamplerDescriptor {
223            mag_filter: FilterMode::Linear,
224            min_filter: FilterMode::Linear,
225            mipmap_filter: FilterMode::Nearest,
226            ..Default::default()
227        };
228
229        let transmittance_lut = render_device.create_sampler(&SamplerDescriptor {
230            label: Some("transmittance_lut_sampler"),
231            ..base_sampler
232        });
233
234        let multiscattering_lut = render_device.create_sampler(&SamplerDescriptor {
235            label: Some("multiscattering_lut_sampler"),
236            ..base_sampler
237        });
238
239        let sky_view_lut = render_device.create_sampler(&SamplerDescriptor {
240            label: Some("sky_view_lut_sampler"),
241            address_mode_u: AddressMode::Repeat,
242            ..base_sampler
243        });
244
245        let aerial_view_lut = render_device.create_sampler(&SamplerDescriptor {
246            label: Some("aerial_view_lut_sampler"),
247            ..base_sampler
248        });
249
250        Self {
251            transmittance_lut,
252            multiscattering_lut,
253            sky_view_lut,
254            aerial_view_lut,
255        }
256    }
257}
258
259#[derive(Resource)]
260pub(crate) struct AtmosphereLutPipelines {
261    pub transmittance_lut: CachedComputePipelineId,
262    pub multiscattering_lut: CachedComputePipelineId,
263    pub sky_view_lut: CachedComputePipelineId,
264    pub aerial_view_lut: CachedComputePipelineId,
265}
266
267impl FromWorld for AtmosphereLutPipelines {
268    fn from_world(world: &mut World) -> Self {
269        let pipeline_cache = world.resource::<PipelineCache>();
270        let layouts = world.resource::<AtmosphereBindGroupLayouts>();
271
272        let transmittance_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
273            label: Some("transmittance_lut_pipeline".into()),
274            layout: vec![layouts.transmittance_lut.clone()],
275            push_constant_ranges: vec![],
276            shader: shaders::TRANSMITTANCE_LUT,
277            shader_defs: vec![],
278            entry_point: "main".into(),
279            zero_initialize_workgroup_memory: false,
280        });
281
282        let multiscattering_lut =
283            pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
284                label: Some("multi_scattering_lut_pipeline".into()),
285                layout: vec![layouts.multiscattering_lut.clone()],
286                push_constant_ranges: vec![],
287                shader: shaders::MULTISCATTERING_LUT,
288                shader_defs: vec![],
289                entry_point: "main".into(),
290                zero_initialize_workgroup_memory: false,
291            });
292
293        let sky_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
294            label: Some("sky_view_lut_pipeline".into()),
295            layout: vec![layouts.sky_view_lut.clone()],
296            push_constant_ranges: vec![],
297            shader: shaders::SKY_VIEW_LUT,
298            shader_defs: vec![],
299            entry_point: "main".into(),
300            zero_initialize_workgroup_memory: false,
301        });
302
303        let aerial_view_lut = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
304            label: Some("aerial_view_lut_pipeline".into()),
305            layout: vec![layouts.aerial_view_lut.clone()],
306            push_constant_ranges: vec![],
307            shader: shaders::AERIAL_VIEW_LUT,
308            shader_defs: vec![],
309            entry_point: "main".into(),
310            zero_initialize_workgroup_memory: false,
311        });
312
313        Self {
314            transmittance_lut,
315            multiscattering_lut,
316            sky_view_lut,
317            aerial_view_lut,
318        }
319    }
320}
321
322#[derive(Component)]
323pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId);
324
325#[derive(Copy, Clone, Hash, PartialEq, Eq)]
326pub(crate) struct RenderSkyPipelineKey {
327    pub msaa_samples: u32,
328    pub hdr: bool,
329    pub dual_source_blending: bool,
330}
331
332impl SpecializedRenderPipeline for RenderSkyBindGroupLayouts {
333    type Key = RenderSkyPipelineKey;
334
335    fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
336        let mut shader_defs = Vec::new();
337
338        if key.msaa_samples > 1 {
339            shader_defs.push("MULTISAMPLED".into());
340        }
341        if key.hdr {
342            shader_defs.push("TONEMAP_IN_SHADER".into());
343        }
344        if key.dual_source_blending {
345            shader_defs.push("DUAL_SOURCE_BLENDING".into());
346        }
347
348        let dst_factor = if key.dual_source_blending {
349            BlendFactor::Src1
350        } else {
351            BlendFactor::SrcAlpha
352        };
353
354        RenderPipelineDescriptor {
355            label: Some(format!("render_sky_pipeline_{}", key.msaa_samples).into()),
356            layout: vec![if key.msaa_samples == 1 {
357                self.render_sky.clone()
358            } else {
359                self.render_sky_msaa.clone()
360            }],
361            push_constant_ranges: vec![],
362            vertex: fullscreen_shader_vertex_state(),
363            primitive: PrimitiveState::default(),
364            depth_stencil: None,
365            multisample: MultisampleState {
366                count: key.msaa_samples,
367                mask: !0,
368                alpha_to_coverage_enabled: false,
369            },
370            zero_initialize_workgroup_memory: false,
371            fragment: Some(FragmentState {
372                shader: shaders::RENDER_SKY.clone(),
373                shader_defs,
374                entry_point: "main".into(),
375                targets: vec![Some(ColorTargetState {
376                    format: TextureFormat::Rgba16Float,
377                    blend: Some(BlendState {
378                        color: BlendComponent {
379                            src_factor: BlendFactor::One,
380                            dst_factor,
381                            operation: BlendOperation::Add,
382                        },
383                        alpha: BlendComponent {
384                            src_factor: BlendFactor::Zero,
385                            dst_factor: BlendFactor::One,
386                            operation: BlendOperation::Add,
387                        },
388                    }),
389                    write_mask: ColorWrites::ALL,
390                })],
391            }),
392        }
393    }
394}
395
396pub(super) fn queue_render_sky_pipelines(
397    views: Query<(Entity, &Camera, &Msaa), With<Atmosphere>>,
398    pipeline_cache: Res<PipelineCache>,
399    layouts: Res<RenderSkyBindGroupLayouts>,
400    mut specializer: ResMut<SpecializedRenderPipelines<RenderSkyBindGroupLayouts>>,
401    render_device: Res<RenderDevice>,
402    mut commands: Commands,
403) {
404    for (entity, camera, msaa) in &views {
405        let id = specializer.specialize(
406            &pipeline_cache,
407            &layouts,
408            RenderSkyPipelineKey {
409                msaa_samples: msaa.samples(),
410                hdr: camera.hdr,
411                dual_source_blending: render_device
412                    .features()
413                    .contains(WgpuFeatures::DUAL_SOURCE_BLENDING),
414            },
415        );
416        commands.entity(entity).insert(RenderSkyPipelineId(id));
417    }
418}
419
420#[derive(Component)]
421pub struct AtmosphereTextures {
422    pub transmittance_lut: CachedTexture,
423    pub multiscattering_lut: CachedTexture,
424    pub sky_view_lut: CachedTexture,
425    pub aerial_view_lut: CachedTexture,
426}
427
428pub(super) fn prepare_atmosphere_textures(
429    views: Query<(Entity, &AtmosphereSettings), With<Atmosphere>>,
430    render_device: Res<RenderDevice>,
431    mut texture_cache: ResMut<TextureCache>,
432    mut commands: Commands,
433) {
434    for (entity, lut_settings) in &views {
435        let transmittance_lut = texture_cache.get(
436            &render_device,
437            TextureDescriptor {
438                label: Some("transmittance_lut"),
439                size: Extent3d {
440                    width: lut_settings.transmittance_lut_size.x,
441                    height: lut_settings.transmittance_lut_size.y,
442                    depth_or_array_layers: 1,
443                },
444                mip_level_count: 1,
445                sample_count: 1,
446                dimension: TextureDimension::D2,
447                format: TextureFormat::Rgba16Float,
448                usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
449                view_formats: &[],
450            },
451        );
452
453        let multiscattering_lut = texture_cache.get(
454            &render_device,
455            TextureDescriptor {
456                label: Some("multiscattering_lut"),
457                size: Extent3d {
458                    width: lut_settings.multiscattering_lut_size.x,
459                    height: lut_settings.multiscattering_lut_size.y,
460                    depth_or_array_layers: 1,
461                },
462                mip_level_count: 1,
463                sample_count: 1,
464                dimension: TextureDimension::D2,
465                format: TextureFormat::Rgba16Float,
466                usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
467                view_formats: &[],
468            },
469        );
470
471        let sky_view_lut = texture_cache.get(
472            &render_device,
473            TextureDescriptor {
474                label: Some("sky_view_lut"),
475                size: Extent3d {
476                    width: lut_settings.sky_view_lut_size.x,
477                    height: lut_settings.sky_view_lut_size.y,
478                    depth_or_array_layers: 1,
479                },
480                mip_level_count: 1,
481                sample_count: 1,
482                dimension: TextureDimension::D2,
483                format: TextureFormat::Rgba16Float,
484                usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
485                view_formats: &[],
486            },
487        );
488
489        let aerial_view_lut = texture_cache.get(
490            &render_device,
491            TextureDescriptor {
492                label: Some("aerial_view_lut"),
493                size: Extent3d {
494                    width: lut_settings.aerial_view_lut_size.x,
495                    height: lut_settings.aerial_view_lut_size.y,
496                    depth_or_array_layers: lut_settings.aerial_view_lut_size.z,
497                },
498                mip_level_count: 1,
499                sample_count: 1,
500                dimension: TextureDimension::D3,
501                format: TextureFormat::Rgba16Float,
502                usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING,
503                view_formats: &[],
504            },
505        );
506
507        commands.entity(entity).insert({
508            AtmosphereTextures {
509                transmittance_lut,
510                multiscattering_lut,
511                sky_view_lut,
512                aerial_view_lut,
513            }
514        });
515    }
516}
517
518#[derive(Resource, Default)]
519pub struct AtmosphereTransforms {
520    uniforms: DynamicUniformBuffer<AtmosphereTransform>,
521}
522
523impl AtmosphereTransforms {
524    #[inline]
525    pub fn uniforms(&self) -> &DynamicUniformBuffer<AtmosphereTransform> {
526        &self.uniforms
527    }
528}
529
530#[derive(ShaderType)]
531pub struct AtmosphereTransform {
532    world_from_atmosphere: Mat4,
533    atmosphere_from_world: Mat4,
534}
535
536#[derive(Component)]
537pub struct AtmosphereTransformsOffset {
538    index: u32,
539}
540
541impl AtmosphereTransformsOffset {
542    #[inline]
543    pub fn index(&self) -> u32 {
544        self.index
545    }
546}
547
548pub(super) fn prepare_atmosphere_transforms(
549    views: Query<(Entity, &ExtractedView), (With<Atmosphere>, With<Camera3d>)>,
550    render_device: Res<RenderDevice>,
551    render_queue: Res<RenderQueue>,
552    mut atmo_uniforms: ResMut<AtmosphereTransforms>,
553    mut commands: Commands,
554) {
555    let atmo_count = views.iter().len();
556    let Some(mut writer) =
557        atmo_uniforms
558            .uniforms
559            .get_writer(atmo_count, &render_device, &render_queue)
560    else {
561        return;
562    };
563
564    for (entity, view) in &views {
565        let world_from_view = view.world_from_view.compute_matrix();
566        let camera_z = world_from_view.z_axis.truncate();
567        let camera_y = world_from_view.y_axis.truncate();
568        let atmo_z = camera_z
569            .with_y(0.0)
570            .try_normalize()
571            .unwrap_or_else(|| camera_y.with_y(0.0).normalize());
572        let atmo_y = Vec3::Y;
573        let atmo_x = atmo_y.cross(atmo_z).normalize();
574        let world_from_atmosphere = Mat4::from_cols(
575            atmo_x.extend(0.0),
576            atmo_y.extend(0.0),
577            atmo_z.extend(0.0),
578            world_from_view.w_axis,
579        );
580
581        let atmosphere_from_world = world_from_atmosphere.inverse();
582
583        commands.entity(entity).insert(AtmosphereTransformsOffset {
584            index: writer.write(&AtmosphereTransform {
585                world_from_atmosphere,
586                atmosphere_from_world,
587            }),
588        });
589    }
590}
591
592#[derive(Component)]
593pub(crate) struct AtmosphereBindGroups {
594    pub transmittance_lut: BindGroup,
595    pub multiscattering_lut: BindGroup,
596    pub sky_view_lut: BindGroup,
597    pub aerial_view_lut: BindGroup,
598    pub render_sky: BindGroup,
599}
600
601pub(super) fn prepare_atmosphere_bind_groups(
602    views: Query<
603        (Entity, &AtmosphereTextures, &ViewDepthTexture, &Msaa),
604        (With<Camera3d>, With<Atmosphere>),
605    >,
606    render_device: Res<RenderDevice>,
607    layouts: Res<AtmosphereBindGroupLayouts>,
608    render_sky_layouts: Res<RenderSkyBindGroupLayouts>,
609    samplers: Res<AtmosphereSamplers>,
610    view_uniforms: Res<ViewUniforms>,
611    lights_uniforms: Res<LightMeta>,
612    atmosphere_transforms: Res<AtmosphereTransforms>,
613    atmosphere_uniforms: Res<ComponentUniforms<Atmosphere>>,
614    settings_uniforms: Res<ComponentUniforms<AtmosphereSettings>>,
615
616    mut commands: Commands,
617) {
618    if views.iter().len() == 0 {
619        return;
620    }
621
622    let atmosphere_binding = atmosphere_uniforms
623        .binding()
624        .expect("Failed to prepare atmosphere bind groups. Atmosphere uniform buffer missing");
625
626    let transforms_binding = atmosphere_transforms
627        .uniforms()
628        .binding()
629        .expect("Failed to prepare atmosphere bind groups. Atmosphere transforms buffer missing");
630
631    let settings_binding = settings_uniforms.binding().expect(
632        "Failed to prepare atmosphere bind groups. AtmosphereSettings uniform buffer missing",
633    );
634
635    let view_binding = view_uniforms
636        .uniforms
637        .binding()
638        .expect("Failed to prepare atmosphere bind groups. View uniform buffer missing");
639
640    let lights_binding = lights_uniforms
641        .view_gpu_lights
642        .binding()
643        .expect("Failed to prepare atmosphere bind groups. Lights uniform buffer missing");
644
645    for (entity, textures, view_depth_texture, msaa) in &views {
646        let transmittance_lut = render_device.create_bind_group(
647            "transmittance_lut_bind_group",
648            &layouts.transmittance_lut,
649            &BindGroupEntries::with_indices((
650                (0, atmosphere_binding.clone()),
651                (1, settings_binding.clone()),
652                (13, &textures.transmittance_lut.default_view),
653            )),
654        );
655
656        let multiscattering_lut = render_device.create_bind_group(
657            "multiscattering_lut_bind_group",
658            &layouts.multiscattering_lut,
659            &BindGroupEntries::with_indices((
660                (0, atmosphere_binding.clone()),
661                (1, settings_binding.clone()),
662                (5, &textures.transmittance_lut.default_view),
663                (6, &samplers.transmittance_lut),
664                (13, &textures.multiscattering_lut.default_view),
665            )),
666        );
667
668        let sky_view_lut = render_device.create_bind_group(
669            "sky_view_lut_bind_group",
670            &layouts.sky_view_lut,
671            &BindGroupEntries::with_indices((
672                (0, atmosphere_binding.clone()),
673                (1, settings_binding.clone()),
674                (2, transforms_binding.clone()),
675                (3, view_binding.clone()),
676                (4, lights_binding.clone()),
677                (5, &textures.transmittance_lut.default_view),
678                (6, &samplers.transmittance_lut),
679                (7, &textures.multiscattering_lut.default_view),
680                (8, &samplers.multiscattering_lut),
681                (13, &textures.sky_view_lut.default_view),
682            )),
683        );
684
685        let aerial_view_lut = render_device.create_bind_group(
686            "sky_view_lut_bind_group",
687            &layouts.aerial_view_lut,
688            &BindGroupEntries::with_indices((
689                (0, atmosphere_binding.clone()),
690                (1, settings_binding.clone()),
691                (3, view_binding.clone()),
692                (4, lights_binding.clone()),
693                (5, &textures.transmittance_lut.default_view),
694                (6, &samplers.transmittance_lut),
695                (7, &textures.multiscattering_lut.default_view),
696                (8, &samplers.multiscattering_lut),
697                (13, &textures.aerial_view_lut.default_view),
698            )),
699        );
700
701        let render_sky = render_device.create_bind_group(
702            "render_sky_bind_group",
703            if *msaa == Msaa::Off {
704                &render_sky_layouts.render_sky
705            } else {
706                &render_sky_layouts.render_sky_msaa
707            },
708            &BindGroupEntries::with_indices((
709                (0, atmosphere_binding.clone()),
710                (1, settings_binding.clone()),
711                (2, transforms_binding.clone()),
712                (3, view_binding.clone()),
713                (4, lights_binding.clone()),
714                (5, &textures.transmittance_lut.default_view),
715                (6, &samplers.transmittance_lut),
716                (9, &textures.sky_view_lut.default_view),
717                (10, &samplers.sky_view_lut),
718                (11, &textures.aerial_view_lut.default_view),
719                (12, &samplers.aerial_view_lut),
720                (13, view_depth_texture.view()),
721            )),
722        );
723
724        commands.entity(entity).insert(AtmosphereBindGroups {
725            transmittance_lut,
726            multiscattering_lut,
727            sky_view_lut,
728            aerial_view_lut,
729            render_sky,
730        });
731    }
732}