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 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 })), (6, sampler(SamplerBindingType::Filtering)),
71 (
72 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 })), (6, sampler(SamplerBindingType::Filtering)),
95 (7, texture_2d(TextureSampleType::Float { filterable: true })), (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 })), (6, sampler(SamplerBindingType::Filtering)),
119 (7, texture_2d(TextureSampleType::Float { filterable: true })), (8, sampler(SamplerBindingType::Filtering)),
121 (
122 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 })), (6, sampler(SamplerBindingType::Filtering)),
157 (9, texture_2d(TextureSampleType::Float { filterable: true })), (10, sampler(SamplerBindingType::Filtering)),
159 (
160 11,
162 texture_3d(TextureSampleType::Float { filterable: true }),
163 ),
164 (12, sampler(SamplerBindingType::Filtering)),
165 (
166 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 })), (6, sampler(SamplerBindingType::Filtering)),
186 (9, texture_2d(TextureSampleType::Float { filterable: true })), (10, sampler(SamplerBindingType::Filtering)),
188 (
189 11,
191 texture_3d(TextureSampleType::Float { filterable: true }),
192 ),
193 (12, sampler(SamplerBindingType::Filtering)),
194 (
195 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}