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 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 })), (6, sampler(SamplerBindingType::Filtering)),
74 (
75 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 })), (6, sampler(SamplerBindingType::Filtering)),
98 (7, texture_2d(TextureSampleType::Float { filterable: true })), (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 })), (6, sampler(SamplerBindingType::Filtering)),
122 (7, texture_2d(TextureSampleType::Float { filterable: true })), (8, sampler(SamplerBindingType::Filtering)),
124 (
125 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 })), (6, sampler(SamplerBindingType::Filtering)),
160 (7, texture_2d(TextureSampleType::Float { filterable: true })), (8, sampler(SamplerBindingType::Filtering)),
162 (9, texture_2d(TextureSampleType::Float { filterable: true })), (10, sampler(SamplerBindingType::Filtering)),
164 (
165 11,
167 texture_3d(TextureSampleType::Float { filterable: true }),
168 ),
169 (12, sampler(SamplerBindingType::Filtering)),
170 (
171 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 })), (6, sampler(SamplerBindingType::Filtering)),
191 (7, texture_2d(TextureSampleType::Float { filterable: true })), (8, sampler(SamplerBindingType::Filtering)),
193 (9, texture_2d(TextureSampleType::Float { filterable: true })), (10, sampler(SamplerBindingType::Filtering)),
195 (
196 11,
198 texture_3d(TextureSampleType::Float { filterable: true }),
199 ),
200 (12, sampler(SamplerBindingType::Filtering)),
201 (
202 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}