bevy_pbr/atmosphere/
resources.rs

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