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