Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_pbr/src/atmosphere/resources.rs
9418 views
1
use crate::{
2
ExtractedAtmosphere, GpuLights, GpuScatteringMedium, LightMeta, ScatteringMediumSampler,
3
};
4
use bevy_asset::{load_embedded_asset, AssetId, Handle};
5
use bevy_camera::{Camera, Camera3d};
6
use bevy_core_pipeline::FullscreenShader;
7
use bevy_derive::Deref;
8
use 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
};
17
use bevy_image::ToExtents;
18
use bevy_light::atmosphere::ScatteringMedium;
19
use bevy_math::{Affine3A, Mat4, Vec3, Vec3A};
20
use 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
};
28
use bevy_shader::Shader;
29
use bevy_utils::default;
30
31
use super::GpuAtmosphereSettings;
32
33
#[derive(Resource)]
34
pub(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)]
42
pub(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
49
impl 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
// scattering medium luts and sampler
59
(5, texture_2d(TextureSampleType::default())),
60
(6, texture_2d(TextureSampleType::default())),
61
(7, sampler(SamplerBindingType::Filtering)),
62
// transmittance lut storage texture
63
(
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
// scattering medium luts and sampler
82
(5, texture_2d(TextureSampleType::default())),
83
(6, texture_2d(TextureSampleType::default())),
84
(7, sampler(SamplerBindingType::Filtering)),
85
// atmosphere luts and sampler
86
(8, texture_2d(TextureSampleType::default())), // transmittance
87
(12, sampler(SamplerBindingType::Filtering)),
88
// multiscattering lut storage texture
89
(
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
// scattering medium luts and sampler
111
(5, texture_2d(TextureSampleType::default())),
112
(6, texture_2d(TextureSampleType::default())),
113
(7, sampler(SamplerBindingType::Filtering)),
114
// atmosphere luts and sampler
115
(8, texture_2d(TextureSampleType::default())), // transmittance
116
(9, texture_2d(TextureSampleType::default())), // multiscattering
117
(12, sampler(SamplerBindingType::Filtering)),
118
// sky view lut storage texture
119
(
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
// scattering medium luts and sampler
140
(5, texture_2d(TextureSampleType::default())),
141
(6, texture_2d(TextureSampleType::default())),
142
(7, sampler(SamplerBindingType::Filtering)),
143
// atmosphere luts and sampler
144
(8, texture_2d(TextureSampleType::default())), // transmittance
145
(9, texture_2d(TextureSampleType::default())), // multiscattering
146
(12, sampler(SamplerBindingType::Filtering)),
147
// eerial view lut storage texture
148
(
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
168
impl 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
// scattering medium luts and sampler
181
(5, texture_2d(TextureSampleType::default())),
182
(6, texture_2d(TextureSampleType::default())),
183
(7, sampler(SamplerBindingType::Filtering)),
184
// atmosphere luts and sampler
185
(8, texture_2d(TextureSampleType::default())), // transmittance
186
(9, texture_2d(TextureSampleType::default())), // multiscattering
187
(10, texture_2d(TextureSampleType::default())), // sky view
188
(11, texture_3d(TextureSampleType::default())), // aerial view
189
(12, sampler(SamplerBindingType::Filtering)),
190
// view depth texture
191
(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
// scattering medium luts and sampler
207
(5, texture_2d(TextureSampleType::default())),
208
(6, texture_2d(TextureSampleType::default())),
209
(7, sampler(SamplerBindingType::Filtering)),
210
// atmosphere luts and sampler
211
(8, texture_2d(TextureSampleType::default())), // transmittance
212
(9, texture_2d(TextureSampleType::default())), // multiscattering
213
(10, texture_2d(TextureSampleType::default())), // sky view
214
(11, texture_3d(TextureSampleType::default())), // aerial view
215
(12, sampler(SamplerBindingType::Filtering)),
216
// view depth texture
217
(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)]
232
pub struct AtmosphereSampler(Sampler);
233
234
impl 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)]
250
pub(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
257
impl 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)]
301
pub(crate) struct RenderSkyPipelineId(pub CachedRenderPipelineId);
302
303
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
304
pub(crate) struct RenderSkyPipelineKey {
305
pub msaa_samples: u32,
306
pub dual_source_blending: bool,
307
}
308
309
impl 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
366
pub(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)]
390
pub 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
397
pub(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.")]
473
struct ScatteringMediumMissingError(AssetId<ScatteringMedium>);
474
475
/// The shader-uniform representation of an Atmosphere.
476
#[derive(Clone, Component, ShaderType)]
477
pub struct GpuAtmosphere {
478
//TODO: rename to Planet later?
479
pub ground_albedo: Vec3,
480
pub bottom_radius: f32,
481
pub top_radius: f32,
482
}
483
484
pub fn prepare_atmosphere_uniforms(
485
mut commands: Commands,
486
atmospheres: Query<(Entity, &ExtractedAtmosphere)>,
487
) -> Result<(), BevyError> {
488
for (entity, atmosphere) in atmospheres {
489
commands.entity(entity).insert(GpuAtmosphere {
490
ground_albedo: atmosphere.ground_albedo,
491
bottom_radius: atmosphere.bottom_radius,
492
top_radius: atmosphere.top_radius,
493
});
494
}
495
Ok(())
496
}
497
498
#[derive(Resource, Default)]
499
pub struct AtmosphereTransforms {
500
uniforms: DynamicUniformBuffer<AtmosphereTransform>,
501
}
502
503
impl AtmosphereTransforms {
504
#[inline]
505
pub fn uniforms(&self) -> &DynamicUniformBuffer<AtmosphereTransform> {
506
&self.uniforms
507
}
508
}
509
510
#[derive(ShaderType)]
511
pub struct AtmosphereTransform {
512
world_from_atmosphere: Mat4,
513
}
514
515
#[derive(Component)]
516
pub struct AtmosphereTransformsOffset {
517
index: u32,
518
}
519
520
impl AtmosphereTransformsOffset {
521
#[inline]
522
pub fn index(&self) -> u32 {
523
self.index
524
}
525
}
526
527
pub(super) fn prepare_atmosphere_transforms(
528
views: Query<(Entity, &ExtractedView), (With<ExtractedAtmosphere>, With<Camera3d>)>,
529
render_device: Res<RenderDevice>,
530
render_queue: Res<RenderQueue>,
531
mut atmo_uniforms: ResMut<AtmosphereTransforms>,
532
mut commands: Commands,
533
) {
534
let atmo_count = views.iter().len();
535
let Some(mut writer) =
536
atmo_uniforms
537
.uniforms
538
.get_writer(atmo_count, &render_device, &render_queue)
539
else {
540
return;
541
};
542
543
for (entity, view) in &views {
544
let world_from_view = view.world_from_view.affine();
545
let camera_z = world_from_view.matrix3.z_axis;
546
let camera_y = world_from_view.matrix3.y_axis;
547
let atmo_z = camera_z
548
.with_y(0.0)
549
.try_normalize()
550
.unwrap_or_else(|| camera_y.with_y(0.0).normalize());
551
let atmo_y = Vec3A::Y;
552
let atmo_x = atmo_y.cross(atmo_z).normalize();
553
let world_from_atmosphere =
554
Affine3A::from_cols(atmo_x, atmo_y, atmo_z, world_from_view.translation);
555
556
let world_from_atmosphere = Mat4::from(world_from_atmosphere);
557
558
commands.entity(entity).insert(AtmosphereTransformsOffset {
559
index: writer.write(&AtmosphereTransform {
560
world_from_atmosphere,
561
}),
562
});
563
}
564
}
565
566
#[derive(Component)]
567
pub(crate) struct AtmosphereBindGroups {
568
pub transmittance_lut: BindGroup,
569
pub multiscattering_lut: BindGroup,
570
pub sky_view_lut: BindGroup,
571
pub aerial_view_lut: BindGroup,
572
pub render_sky: BindGroup,
573
}
574
575
#[derive(Copy, Clone, Debug, thiserror::Error)]
576
enum AtmosphereBindGroupError {
577
#[error("Failed to prepare atmosphere bind groups. Atmosphere uniform buffer missing")]
578
Atmosphere,
579
#[error(
580
"Failed to prepare atmosphere bind groups. AtmosphereTransforms uniform buffer missing"
581
)]
582
Transforms,
583
#[error("Failed to prepare atmosphere bind groups. AtmosphereSettings uniform buffer missing")]
584
Settings,
585
#[error("Failed to prepare atmosphere bind groups. View uniform buffer missing")]
586
ViewUniforms,
587
#[error("Failed to prepare atmosphere bind groups. Light uniform buffer missing")]
588
LightUniforms,
589
}
590
591
pub(super) fn prepare_atmosphere_bind_groups(
592
views: Query<
593
(
594
Entity,
595
&ExtractedAtmosphere,
596
&AtmosphereTextures,
597
&ViewDepthTexture,
598
&Msaa,
599
),
600
(With<Camera3d>, With<ExtractedAtmosphere>),
601
>,
602
render_device: Res<RenderDevice>,
603
layouts: Res<AtmosphereBindGroupLayouts>,
604
render_sky_layouts: Res<RenderSkyBindGroupLayouts>,
605
atmosphere_sampler: Res<AtmosphereSampler>,
606
view_uniforms: Res<ViewUniforms>,
607
lights_uniforms: Res<LightMeta>,
608
atmosphere_transforms: Res<AtmosphereTransforms>,
609
atmosphere_uniforms: Res<ComponentUniforms<GpuAtmosphere>>,
610
settings_uniforms: Res<ComponentUniforms<GpuAtmosphereSettings>>,
611
gpu_media: Res<RenderAssets<GpuScatteringMedium>>,
612
medium_sampler: Res<ScatteringMediumSampler>,
613
pipeline_cache: Res<PipelineCache>,
614
mut commands: Commands,
615
) -> Result<(), BevyError> {
616
if views.iter().len() == 0 {
617
return Ok(());
618
}
619
620
let atmosphere_binding = atmosphere_uniforms
621
.binding()
622
.ok_or(AtmosphereBindGroupError::Atmosphere)?;
623
624
let transforms_binding = atmosphere_transforms
625
.uniforms()
626
.binding()
627
.ok_or(AtmosphereBindGroupError::Transforms)?;
628
629
let settings_binding = settings_uniforms
630
.binding()
631
.ok_or(AtmosphereBindGroupError::Settings)?;
632
633
let view_binding = view_uniforms
634
.uniforms
635
.binding()
636
.ok_or(AtmosphereBindGroupError::ViewUniforms)?;
637
638
let lights_binding = lights_uniforms
639
.view_gpu_lights
640
.binding()
641
.ok_or(AtmosphereBindGroupError::LightUniforms)?;
642
643
for (entity, atmosphere, textures, view_depth_texture, msaa) in &views {
644
let gpu_medium = gpu_media
645
.get(atmosphere.medium)
646
.ok_or(ScatteringMediumMissingError(atmosphere.medium))?;
647
648
let transmittance_lut = render_device.create_bind_group(
649
"transmittance_lut_bind_group",
650
&pipeline_cache.get_bind_group_layout(&layouts.transmittance_lut),
651
&BindGroupEntries::with_indices((
652
// uniforms
653
(0, atmosphere_binding.clone()),
654
(1, settings_binding.clone()),
655
// scattering medium luts and sampler
656
(5, &gpu_medium.density_lut_view),
657
(6, &gpu_medium.scattering_lut_view),
658
(7, medium_sampler.sampler()),
659
// transmittance lut storage texture
660
(13, &textures.transmittance_lut.default_view),
661
)),
662
);
663
664
let multiscattering_lut = render_device.create_bind_group(
665
"multiscattering_lut_bind_group",
666
&pipeline_cache.get_bind_group_layout(&layouts.multiscattering_lut),
667
&BindGroupEntries::with_indices((
668
// uniforms
669
(0, atmosphere_binding.clone()),
670
(1, settings_binding.clone()),
671
// scattering medium luts and sampler
672
(5, &gpu_medium.density_lut_view),
673
(6, &gpu_medium.scattering_lut_view),
674
(7, medium_sampler.sampler()),
675
// atmosphere luts and sampler
676
(8, &textures.transmittance_lut.default_view),
677
(12, &**atmosphere_sampler),
678
// multiscattering lut storage texture
679
(13, &textures.multiscattering_lut.default_view),
680
)),
681
);
682
683
let sky_view_lut = render_device.create_bind_group(
684
"sky_view_lut_bind_group",
685
&pipeline_cache.get_bind_group_layout(&layouts.sky_view_lut),
686
&BindGroupEntries::with_indices((
687
// uniforms
688
(0, atmosphere_binding.clone()),
689
(1, settings_binding.clone()),
690
(2, transforms_binding.clone()),
691
(3, view_binding.clone()),
692
(4, lights_binding.clone()),
693
// scattering medium luts and sampler
694
(5, &gpu_medium.density_lut_view),
695
(6, &gpu_medium.scattering_lut_view),
696
(7, medium_sampler.sampler()),
697
// atmosphere luts and sampler
698
(8, &textures.transmittance_lut.default_view),
699
(9, &textures.multiscattering_lut.default_view),
700
(12, &**atmosphere_sampler),
701
// sky view lut storage texture
702
(13, &textures.sky_view_lut.default_view),
703
)),
704
);
705
706
let aerial_view_lut = render_device.create_bind_group(
707
"sky_view_lut_bind_group",
708
&pipeline_cache.get_bind_group_layout(&layouts.aerial_view_lut),
709
&BindGroupEntries::with_indices((
710
// uniforms
711
(0, atmosphere_binding.clone()),
712
(1, settings_binding.clone()),
713
(3, view_binding.clone()),
714
(4, lights_binding.clone()),
715
// scattering medium luts and sampler
716
(5, &gpu_medium.density_lut_view),
717
(6, &gpu_medium.scattering_lut_view),
718
(7, medium_sampler.sampler()),
719
// atmosphere luts and sampler
720
(8, &textures.transmittance_lut.default_view),
721
(9, &textures.multiscattering_lut.default_view),
722
(12, &**atmosphere_sampler),
723
// aerial view lut storage texture
724
(13, &textures.aerial_view_lut.default_view),
725
)),
726
);
727
728
let render_sky = render_device.create_bind_group(
729
"render_sky_bind_group",
730
&pipeline_cache.get_bind_group_layout(if *msaa == Msaa::Off {
731
&render_sky_layouts.render_sky
732
} else {
733
&render_sky_layouts.render_sky_msaa
734
}),
735
&BindGroupEntries::with_indices((
736
// uniforms
737
(0, atmosphere_binding.clone()),
738
(1, settings_binding.clone()),
739
(2, transforms_binding.clone()),
740
(3, view_binding.clone()),
741
(4, lights_binding.clone()),
742
// scattering medium luts and sampler
743
(5, &gpu_medium.density_lut_view),
744
(6, &gpu_medium.scattering_lut_view),
745
(7, medium_sampler.sampler()),
746
// atmosphere luts and sampler
747
(8, &textures.transmittance_lut.default_view),
748
(9, &textures.multiscattering_lut.default_view),
749
(10, &textures.sky_view_lut.default_view),
750
(11, &textures.aerial_view_lut.default_view),
751
(12, &**atmosphere_sampler),
752
// view depth texture
753
(13, view_depth_texture.view()),
754
)),
755
);
756
757
commands.entity(entity).insert(AtmosphereBindGroups {
758
transmittance_lut,
759
multiscattering_lut,
760
sky_view_lut,
761
aerial_view_lut,
762
render_sky,
763
});
764
}
765
766
Ok(())
767
}
768
769
#[derive(ShaderType)]
770
#[repr(C)]
771
pub(crate) struct AtmosphereData {
772
pub atmosphere: GpuAtmosphere,
773
pub settings: GpuAtmosphereSettings,
774
}
775
776
pub fn init_atmosphere_buffer(mut commands: Commands) {
777
commands.insert_resource(AtmosphereBuffer {
778
buffer: StorageBuffer::from(AtmosphereData {
779
atmosphere: GpuAtmosphere {
780
ground_albedo: Vec3::ZERO,
781
bottom_radius: 0.0,
782
top_radius: 0.0,
783
},
784
settings: GpuAtmosphereSettings::default(),
785
}),
786
});
787
}
788
789
#[derive(Resource)]
790
pub struct AtmosphereBuffer {
791
pub(crate) buffer: StorageBuffer<AtmosphereData>,
792
}
793
794
pub(crate) fn write_atmosphere_buffer(
795
device: Res<RenderDevice>,
796
queue: Res<RenderQueue>,
797
atmosphere_entity: Query<(&GpuAtmosphere, &GpuAtmosphereSettings), With<Camera3d>>,
798
mut atmosphere_buffer: ResMut<AtmosphereBuffer>,
799
) {
800
let Ok((atmosphere, settings)) = atmosphere_entity.single() else {
801
return;
802
};
803
804
atmosphere_buffer.buffer.set(AtmosphereData {
805
atmosphere: atmosphere.clone(),
806
settings: settings.clone(),
807
});
808
atmosphere_buffer.buffer.write_buffer(&device, &queue);
809
}
810
811