Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_pbr/src/render/mesh_view_bindings.rs
9400 views
1
use alloc::sync::Arc;
2
use bevy_core_pipeline::{
3
oit::{resolve::is_oit_supported, OitBuffers, OrderIndependentTransparencySettings},
4
prepass::ViewPrepassTextures,
5
tonemapping::{
6
get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,
7
},
8
};
9
use bevy_derive::{Deref, DerefMut};
10
use bevy_ecs::{
11
component::Component,
12
entity::Entity,
13
query::Has,
14
resource::Resource,
15
system::{Commands, Query, Res},
16
world::{FromWorld, World},
17
};
18
use bevy_image::BevyDefault as _;
19
use bevy_light::{EnvironmentMapLight, IrradianceVolume};
20
use bevy_math::Vec4;
21
use bevy_render::{
22
globals::{GlobalsBuffer, GlobalsUniform},
23
render_asset::RenderAssets,
24
render_resource::{binding_types::*, *},
25
renderer::{RenderAdapter, RenderDevice},
26
texture::{FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage},
27
view::{
28
Msaa, RenderVisibilityRanges, ViewUniform, ViewUniforms,
29
VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
30
},
31
};
32
use core::{array, num::NonZero};
33
34
use crate::{
35
contact_shadows::{
36
ContactShadowsBuffer, ContactShadowsUniform, ViewContactShadowsUniformOffset,
37
},
38
decal::{
39
self,
40
clustered::{
41
DecalsBuffer, RenderClusteredDecals, RenderViewClusteredDecalBindGroupEntries,
42
},
43
},
44
environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},
45
irradiance_volume::{
46
self, RenderViewIrradianceVolumeBindGroupEntries, IRRADIANCE_VOLUMES_ARE_USABLE,
47
},
48
prepass,
49
resources::{AtmosphereBuffer, AtmosphereData, AtmosphereSampler, AtmosphereTextures},
50
Bluenoise, EnvironmentMapUniformBuffer, ExtractedAtmosphere, FogMeta,
51
GlobalClusterableObjectMeta, GpuClusteredLights, GpuFog, GpuLights, LightMeta,
52
LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes,
53
ScreenSpaceAmbientOcclusionResources, ScreenSpaceReflectionsBuffer,
54
ScreenSpaceReflectionsUniform, ShadowSamplers, ViewClusterBindings, ViewShadowBindings,
55
ViewTransmissionTexture, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
56
};
57
58
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
59
use bevy_render::render_resource::binding_types::texture_cube;
60
61
#[cfg(debug_assertions)]
62
use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};
63
64
#[derive(Clone)]
65
pub struct MeshPipelineViewLayout {
66
pub main_layout: BindGroupLayoutDescriptor,
67
pub binding_array_layout: BindGroupLayoutDescriptor,
68
pub empty_layout: BindGroupLayoutDescriptor,
69
70
#[cfg(debug_assertions)]
71
pub texture_count: usize,
72
}
73
74
bitflags::bitflags! {
75
/// A key that uniquely identifies a [`MeshPipelineViewLayout`].
76
///
77
/// Used to generate all possible layouts for the mesh pipeline in [`generate_view_layouts`],
78
/// so special care must be taken to not add too many flags, as the number of possible layouts
79
/// will grow exponentially.
80
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
81
#[repr(transparent)]
82
pub struct MeshPipelineViewLayoutKey: u32 {
83
const MULTISAMPLED = 1 << 0;
84
const DEPTH_PREPASS = 1 << 1;
85
const NORMAL_PREPASS = 1 << 2;
86
const MOTION_VECTOR_PREPASS = 1 << 3;
87
const DEFERRED_PREPASS = 1 << 4;
88
const OIT_ENABLED = 1 << 5;
89
const ATMOSPHERE = 1 << 6;
90
const STBN = 1 << 7;
91
}
92
}
93
94
impl MeshPipelineViewLayoutKey {
95
// The number of possible layouts
96
pub const COUNT: usize = Self::all().bits() as usize + 1;
97
98
/// Builds a unique label for each layout based on the flags
99
pub fn label(&self) -> String {
100
use MeshPipelineViewLayoutKey as Key;
101
102
format!(
103
"mesh_view_layout{}{}{}{}{}{}{}{}",
104
if self.contains(Key::MULTISAMPLED) {
105
"_multisampled"
106
} else {
107
Default::default()
108
},
109
if self.contains(Key::DEPTH_PREPASS) {
110
"_depth"
111
} else {
112
Default::default()
113
},
114
if self.contains(Key::NORMAL_PREPASS) {
115
"_normal"
116
} else {
117
Default::default()
118
},
119
if self.contains(Key::MOTION_VECTOR_PREPASS) {
120
"_motion"
121
} else {
122
Default::default()
123
},
124
if self.contains(Key::DEFERRED_PREPASS) {
125
"_deferred"
126
} else {
127
Default::default()
128
},
129
if self.contains(Key::OIT_ENABLED) {
130
"_oit"
131
} else {
132
Default::default()
133
},
134
if self.contains(Key::ATMOSPHERE) {
135
"_atmosphere"
136
} else {
137
Default::default()
138
},
139
if self.contains(Key::STBN) {
140
"_stbn"
141
} else {
142
Default::default()
143
},
144
)
145
}
146
}
147
148
impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {
149
fn from(value: MeshPipelineKey) -> Self {
150
let mut result = MeshPipelineViewLayoutKey::empty();
151
152
if value.msaa_samples() > 1 {
153
result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
154
}
155
if value.contains(MeshPipelineKey::DEPTH_PREPASS) {
156
result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
157
}
158
if value.contains(MeshPipelineKey::NORMAL_PREPASS) {
159
result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
160
}
161
if value.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
162
result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
163
}
164
if value.contains(MeshPipelineKey::DEFERRED_PREPASS) {
165
result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
166
}
167
if value.contains(MeshPipelineKey::OIT_ENABLED) {
168
result |= MeshPipelineViewLayoutKey::OIT_ENABLED;
169
}
170
if value.contains(MeshPipelineKey::ATMOSPHERE) {
171
result |= MeshPipelineViewLayoutKey::ATMOSPHERE;
172
}
173
174
if cfg!(feature = "bluenoise_texture") {
175
result |= MeshPipelineViewLayoutKey::STBN;
176
}
177
178
result
179
}
180
}
181
182
impl From<Msaa> for MeshPipelineViewLayoutKey {
183
fn from(value: Msaa) -> Self {
184
let mut result = MeshPipelineViewLayoutKey::empty();
185
186
if value.samples() > 1 {
187
result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
188
}
189
190
result
191
}
192
}
193
194
impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {
195
fn from(value: Option<&ViewPrepassTextures>) -> Self {
196
let mut result = MeshPipelineViewLayoutKey::empty();
197
198
if let Some(prepass_textures) = value {
199
if prepass_textures.depth.is_some() {
200
result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
201
}
202
if prepass_textures.normal.is_some() {
203
result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
204
}
205
if prepass_textures.motion_vectors.is_some() {
206
result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
207
}
208
if prepass_textures.deferred.is_some() {
209
result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
210
}
211
}
212
213
result
214
}
215
}
216
217
pub(crate) fn buffer_layout(
218
buffer_binding_type: BufferBindingType,
219
has_dynamic_offset: bool,
220
min_binding_size: Option<NonZero<u64>>,
221
) -> BindGroupLayoutEntryBuilder {
222
match buffer_binding_type {
223
BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),
224
BufferBindingType::Storage { read_only } => {
225
if read_only {
226
storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)
227
} else {
228
storage_buffer_sized(has_dynamic_offset, min_binding_size)
229
}
230
}
231
}
232
}
233
234
/// Returns the appropriate bind group layout vec based on the parameters
235
pub fn layout_entries(
236
clustered_forward_buffer_binding_type: BufferBindingType,
237
visibility_ranges_buffer_binding_type: BufferBindingType,
238
layout_key: MeshPipelineViewLayoutKey,
239
render_device: &RenderDevice,
240
render_adapter: &RenderAdapter,
241
) -> [Vec<BindGroupLayoutEntry>; 2] {
242
// EnvironmentMapLight
243
let environment_map_entries =
244
environment_map::get_bind_group_layout_entries(render_device, render_adapter);
245
246
let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(
247
ShaderStages::FRAGMENT,
248
(
249
// View
250
(
251
0,
252
uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
253
),
254
// Lights
255
(1, uniform_buffer::<GpuLights>(true)),
256
// Point Shadow Texture Cube Array
257
(
258
2,
259
#[cfg(all(
260
not(target_abi = "sim"),
261
any(
262
not(feature = "webgl"),
263
not(target_arch = "wasm32"),
264
feature = "webgpu"
265
)
266
))]
267
texture_cube_array(TextureSampleType::Depth),
268
#[cfg(any(
269
target_abi = "sim",
270
all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))
271
))]
272
texture_cube(TextureSampleType::Depth),
273
),
274
// Point Shadow Texture Array Comparison Sampler
275
(3, sampler(SamplerBindingType::Comparison)),
276
// Point Shadow Texture Array Linear Sampler
277
#[cfg(feature = "experimental_pbr_pcss")]
278
(4, sampler(SamplerBindingType::Filtering)),
279
// Directional Shadow Texture Array
280
(
281
5,
282
#[cfg(any(
283
not(feature = "webgl"),
284
not(target_arch = "wasm32"),
285
feature = "webgpu"
286
))]
287
texture_2d_array(TextureSampleType::Depth),
288
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
289
texture_2d(TextureSampleType::Depth),
290
),
291
// Directional Shadow Texture Array Comparison Sampler
292
(6, sampler(SamplerBindingType::Comparison)),
293
// Directional Shadow Texture Array Linear Sampler
294
#[cfg(feature = "experimental_pbr_pcss")]
295
(7, sampler(SamplerBindingType::Filtering)),
296
// PointLights
297
(
298
8,
299
buffer_layout(
300
clustered_forward_buffer_binding_type,
301
false,
302
Some(GpuClusteredLights::min_size(
303
clustered_forward_buffer_binding_type,
304
)),
305
),
306
),
307
// ClusteredLightIndexLists
308
(
309
9,
310
buffer_layout(
311
clustered_forward_buffer_binding_type,
312
false,
313
Some(
314
ViewClusterBindings::min_size_clusterable_object_index_lists(
315
clustered_forward_buffer_binding_type,
316
),
317
),
318
),
319
),
320
// ClusterOffsetsAndCounts
321
(
322
10,
323
buffer_layout(
324
clustered_forward_buffer_binding_type,
325
false,
326
Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
327
clustered_forward_buffer_binding_type,
328
)),
329
),
330
),
331
// Globals
332
(
333
11,
334
uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
335
),
336
// Fog
337
(12, uniform_buffer::<GpuFog>(true)),
338
// Light probes
339
(13, uniform_buffer::<LightProbesUniform>(true)),
340
// Visibility ranges
341
(
342
14,
343
buffer_layout(
344
visibility_ranges_buffer_binding_type,
345
false,
346
Some(Vec4::min_size()),
347
)
348
.visibility(ShaderStages::VERTEX),
349
),
350
// Screen space reflection settings
351
(15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),
352
// Contact shadows settings
353
(16, uniform_buffer::<ContactShadowsUniform>(true)),
354
// Screen space ambient occlusion texture
355
(
356
17,
357
texture_2d(TextureSampleType::Float { filterable: false }),
358
),
359
(18, environment_map_entries[3]),
360
),
361
);
362
363
// Tonemapping
364
let tonemapping_lut_entries = get_lut_bind_group_layout_entries();
365
entries = entries.extend_with_indices((
366
(19, tonemapping_lut_entries[0]),
367
(20, tonemapping_lut_entries[1]),
368
));
369
370
// Prepass
371
if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))
372
|| (cfg!(all(feature = "webgl", target_arch = "wasm32"))
373
&& !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))
374
{
375
for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)
376
.iter()
377
.zip([21, 22, 23, 24])
378
{
379
if let Some(entry) = entry {
380
entries = entries.extend_with_indices(((binding as u32, *entry),));
381
}
382
}
383
}
384
385
// View Transmission Texture
386
entries = entries.extend_with_indices((
387
(
388
25,
389
texture_2d(TextureSampleType::Float { filterable: true }),
390
),
391
(26, sampler(SamplerBindingType::Filtering)),
392
));
393
394
// OIT
395
if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {
396
// Check if we can use OIT. This is a hack to avoid errors on webgl --
397
// the OIT plugin will warn the user that OIT is not supported on their
398
// platform, so we don't need to do it here.
399
if is_oit_supported(render_adapter, render_device, false) {
400
entries = entries.extend_with_indices((
401
(
402
27,
403
uniform_buffer::<OrderIndependentTransparencySettings>(true),
404
),
405
// oit_nodes_capacity
406
(28, uniform_buffer::<u32>(false)),
407
// oit_nodes
408
(29, storage_buffer_sized(false, None)),
409
// oit_heads,
410
(30, storage_buffer_sized(false, None)),
411
// oit_atomic_counter
412
(
413
31,
414
storage_buffer_sized(false, NonZero::<u64>::new(size_of::<u32>() as u64)),
415
),
416
));
417
}
418
}
419
420
// Atmosphere
421
if layout_key.contains(MeshPipelineViewLayoutKey::ATMOSPHERE) {
422
entries = entries.extend_with_indices((
423
// transmittance LUT
424
(
425
32,
426
texture_2d(TextureSampleType::Float { filterable: true }),
427
),
428
(33, sampler(SamplerBindingType::Filtering)),
429
// atmosphere data buffer
430
(34, storage_buffer_read_only::<AtmosphereData>(false)),
431
));
432
}
433
434
// Blue noise
435
if layout_key.contains(MeshPipelineViewLayoutKey::STBN) {
436
entries = entries.extend_with_indices(((
437
35,
438
texture_2d_array(TextureSampleType::Float { filterable: false }),
439
),));
440
}
441
442
let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);
443
binding_array_entries = binding_array_entries.extend_with_indices((
444
(0, environment_map_entries[0]),
445
(1, environment_map_entries[1]),
446
(2, environment_map_entries[2]),
447
));
448
449
// Irradiance volumes
450
if IRRADIANCE_VOLUMES_ARE_USABLE {
451
let irradiance_volume_entries =
452
irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter);
453
binding_array_entries = binding_array_entries.extend_with_indices((
454
(3, irradiance_volume_entries[0]),
455
(4, irradiance_volume_entries[1]),
456
));
457
}
458
459
// Clustered decals
460
if let Some(clustered_decal_entries) =
461
decal::clustered::get_bind_group_layout_entries(render_device, render_adapter)
462
{
463
binding_array_entries = binding_array_entries.extend_with_indices((
464
(5, clustered_decal_entries[0]),
465
(6, clustered_decal_entries[1]),
466
(7, clustered_decal_entries[2]),
467
));
468
}
469
470
[entries.to_vec(), binding_array_entries.to_vec()]
471
}
472
473
/// Stores the view layouts for every combination of pipeline keys.
474
///
475
/// This is wrapped in an [`Arc`] so that it can be efficiently cloned and
476
/// placed inside specializable pipeline types.
477
#[derive(Resource, Clone, Deref, DerefMut)]
478
pub struct MeshPipelineViewLayouts(
479
pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,
480
);
481
482
impl FromWorld for MeshPipelineViewLayouts {
483
fn from_world(world: &mut World) -> Self {
484
// Generates all possible view layouts for the mesh pipeline, based on all combinations of
485
// [`MeshPipelineViewLayoutKey`] flags.
486
487
let render_device = world.resource::<RenderDevice>();
488
let render_adapter = world.resource::<RenderAdapter>();
489
490
let clustered_forward_buffer_binding_type = render_device
491
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
492
let visibility_ranges_buffer_binding_type = render_device
493
.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
494
495
Self(Arc::new(array::from_fn(|i| {
496
let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);
497
let entries = layout_entries(
498
clustered_forward_buffer_binding_type,
499
visibility_ranges_buffer_binding_type,
500
key,
501
render_device,
502
render_adapter,
503
);
504
#[cfg(debug_assertions)]
505
let texture_count: usize = entries
506
.iter()
507
.flat_map(|e| {
508
e.iter()
509
.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))
510
})
511
.count();
512
513
MeshPipelineViewLayout {
514
main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),
515
binding_array_layout: BindGroupLayoutDescriptor::new(
516
format!("{}_binding_array", key.label()),
517
&entries[1],
518
),
519
empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),
520
#[cfg(debug_assertions)]
521
texture_count,
522
}
523
})))
524
}
525
}
526
527
impl MeshPipelineViewLayouts {
528
pub fn get_view_layout(
529
&self,
530
layout_key: MeshPipelineViewLayoutKey,
531
) -> &MeshPipelineViewLayout {
532
let index = layout_key.bits() as usize;
533
let layout = &self[index];
534
535
#[cfg(debug_assertions)]
536
if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {
537
// Issue our own warning here because Naga's error message is a bit cryptic in this situation
538
once!(warn!("Too many textures in mesh pipeline view layout, this might cause us to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments."));
539
}
540
541
layout
542
}
543
}
544
545
/// Generates all possible view layouts for the mesh pipeline, based on all combinations of
546
/// [`MeshPipelineViewLayoutKey`] flags.
547
#[deprecated(since = "0.16.0", note = "Use `layout_entries` instead")]
548
pub fn generate_view_layouts(
549
render_device: &RenderDevice,
550
render_adapter: &RenderAdapter,
551
clustered_forward_buffer_binding_type: BufferBindingType,
552
visibility_ranges_buffer_binding_type: BufferBindingType,
553
) -> [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT] {
554
array::from_fn(|i| {
555
let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);
556
let entries = layout_entries(
557
clustered_forward_buffer_binding_type,
558
visibility_ranges_buffer_binding_type,
559
key,
560
render_device,
561
render_adapter,
562
);
563
564
#[cfg(debug_assertions)]
565
let texture_count: usize = entries
566
.iter()
567
.flat_map(|e| {
568
e.iter()
569
.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))
570
})
571
.count();
572
573
MeshPipelineViewLayout {
574
main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),
575
binding_array_layout: BindGroupLayoutDescriptor::new(
576
format!("{}_binding_array", key.label()),
577
&entries[1],
578
),
579
empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),
580
#[cfg(debug_assertions)]
581
texture_count,
582
}
583
})
584
}
585
586
#[derive(Component)]
587
pub struct MeshViewBindGroup {
588
pub main: BindGroup,
589
pub binding_array: BindGroup,
590
pub empty: BindGroup,
591
}
592
593
pub fn prepare_mesh_view_bind_groups(
594
mut commands: Commands,
595
(render_device, pipeline_cache, render_adapter): (
596
Res<RenderDevice>,
597
Res<PipelineCache>,
598
Res<RenderAdapter>,
599
),
600
mesh_pipeline: Res<MeshPipeline>,
601
shadow_samplers: Res<ShadowSamplers>,
602
(light_meta, global_clusterable_object_meta): (
603
Res<LightMeta>,
604
Res<GlobalClusterableObjectMeta>,
605
),
606
fog_meta: Res<FogMeta>,
607
(view_uniforms, environment_map_uniform): (Res<ViewUniforms>, Res<EnvironmentMapUniformBuffer>),
608
views: Query<(
609
Entity,
610
&ViewShadowBindings,
611
&ViewClusterBindings,
612
&Msaa,
613
Option<&ScreenSpaceAmbientOcclusionResources>,
614
Option<&ViewPrepassTextures>,
615
Option<&ViewTransmissionTexture>,
616
&Tonemapping,
617
Option<&RenderViewLightProbes<EnvironmentMapLight>>,
618
Option<&RenderViewLightProbes<IrradianceVolume>>,
619
Has<OrderIndependentTransparencySettings>,
620
Option<&AtmosphereTextures>,
621
Has<ExtractedAtmosphere>,
622
Option<&ViewContactShadowsUniformOffset>,
623
)>,
624
(images, mut fallback_images, fallback_image, fallback_image_zero): (
625
Res<RenderAssets<GpuImage>>,
626
FallbackImageMsaa,
627
Res<FallbackImage>,
628
Res<FallbackImageZero>,
629
),
630
globals_buffer: Res<GlobalsBuffer>,
631
tonemapping_luts: Res<TonemappingLuts>,
632
light_probes_buffer: Res<LightProbesBuffer>,
633
visibility_ranges: Res<RenderVisibilityRanges>,
634
(ssr_buffer, contact_shadows_buffer): (
635
Res<ScreenSpaceReflectionsBuffer>,
636
Res<ContactShadowsBuffer>,
637
),
638
oit_buffers: Res<OitBuffers>,
639
(decals_buffer, render_decals, atmosphere_buffer, atmosphere_sampler, blue_noise): (
640
Res<DecalsBuffer>,
641
Res<RenderClusteredDecals>,
642
Option<Res<AtmosphereBuffer>>,
643
Option<Res<AtmosphereSampler>>,
644
Res<Bluenoise>,
645
),
646
) {
647
if let (
648
Some(view_binding),
649
Some(light_binding),
650
Some(clusterable_objects_binding),
651
Some(globals),
652
Some(fog_binding),
653
Some(light_probes_binding),
654
Some(visibility_ranges_buffer),
655
Some(ssr_binding),
656
Some(contact_shadows_binding),
657
Some(environment_map_binding),
658
) = (
659
view_uniforms.uniforms.binding(),
660
light_meta.view_gpu_lights.binding(),
661
global_clusterable_object_meta
662
.gpu_clustered_lights
663
.binding(),
664
globals_buffer.buffer.binding(),
665
fog_meta.gpu_fogs.binding(),
666
light_probes_buffer.binding(),
667
visibility_ranges.buffer().buffer(),
668
ssr_buffer.binding(),
669
contact_shadows_buffer.0.binding(),
670
environment_map_uniform.binding(),
671
) {
672
for (
673
entity,
674
shadow_bindings,
675
cluster_bindings,
676
msaa,
677
ssao_resources,
678
prepass_textures,
679
transmission_texture,
680
tonemapping,
681
render_view_environment_maps,
682
render_view_irradiance_volumes,
683
has_oit,
684
atmosphere_textures,
685
has_atmosphere,
686
_contact_shadows_offset,
687
) in &views
688
{
689
let fallback_ssao = fallback_images
690
.image_for_samplecount(1, TextureFormat::bevy_default())
691
.texture_view
692
.clone();
693
let ssao_view = ssao_resources
694
.map(|t| &t.screen_space_ambient_occlusion_texture.default_view)
695
.unwrap_or(&fallback_ssao);
696
697
let mut layout_key = MeshPipelineViewLayoutKey::from(*msaa)
698
| MeshPipelineViewLayoutKey::from(prepass_textures);
699
if has_oit {
700
layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;
701
}
702
if has_atmosphere {
703
layout_key |= MeshPipelineViewLayoutKey::ATMOSPHERE;
704
}
705
if cfg!(feature = "bluenoise_texture") {
706
layout_key |= MeshPipelineViewLayoutKey::STBN;
707
}
708
709
let layout = mesh_pipeline.get_view_layout(layout_key);
710
711
let mut entries = DynamicBindGroupEntries::new_with_indices((
712
(0, view_binding.clone()),
713
(1, light_binding.clone()),
714
(2, &shadow_bindings.point_light_depth_texture_view),
715
(3, &shadow_samplers.point_light_comparison_sampler),
716
#[cfg(feature = "experimental_pbr_pcss")]
717
(4, &shadow_samplers.point_light_linear_sampler),
718
(5, &shadow_bindings.directional_light_depth_texture_view),
719
(6, &shadow_samplers.directional_light_comparison_sampler),
720
#[cfg(feature = "experimental_pbr_pcss")]
721
(7, &shadow_samplers.directional_light_linear_sampler),
722
(8, clusterable_objects_binding.clone()),
723
(
724
9,
725
cluster_bindings
726
.clusterable_object_index_lists_binding()
727
.unwrap(),
728
),
729
(10, cluster_bindings.offsets_and_counts_binding().unwrap()),
730
(11, globals.clone()),
731
(12, fog_binding.clone()),
732
(13, light_probes_binding.clone()),
733
(14, visibility_ranges_buffer.as_entire_binding()),
734
(15, ssr_binding.clone()),
735
(16, contact_shadows_binding.clone()),
736
(17, ssao_view),
737
));
738
739
entries = entries.extend_with_indices(((18, environment_map_binding.clone()),));
740
741
let lut_bindings =
742
get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);
743
entries = entries.extend_with_indices(((19, lut_bindings.0), (20, lut_bindings.1)));
744
745
// When using WebGL, we can't have a depth texture with multisampling
746
let prepass_bindings;
747
if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1
748
{
749
prepass_bindings = prepass::get_bindings(prepass_textures);
750
for (binding, index) in prepass_bindings
751
.iter()
752
.map(Option::as_ref)
753
.zip([21, 22, 23, 24])
754
.flat_map(|(b, i)| b.map(|b| (b, i)))
755
{
756
entries = entries.extend_with_indices(((index, binding),));
757
}
758
};
759
760
let transmission_view = transmission_texture
761
.map(|transmission| &transmission.view)
762
.unwrap_or(&fallback_image_zero.texture_view);
763
764
let transmission_sampler = transmission_texture
765
.map(|transmission| &transmission.sampler)
766
.unwrap_or(&fallback_image_zero.sampler);
767
768
entries =
769
entries.extend_with_indices(((25, transmission_view), (26, transmission_sampler)));
770
771
if has_oit
772
&& let (
773
Some(oit_settings_binding),
774
Some(oit_nodes_capacity),
775
Some(oit_nodes),
776
Some(oit_heads),
777
Some(oit_atomic_counter),
778
) = (
779
oit_buffers.settings.binding(),
780
oit_buffers.nodes_capacity.binding(),
781
oit_buffers.nodes.binding(),
782
oit_buffers.heads.binding(),
783
oit_buffers.atomic_counter.binding(),
784
)
785
{
786
entries = entries.extend_with_indices((
787
(27, oit_settings_binding),
788
(28, oit_nodes_capacity),
789
(29, oit_nodes),
790
(30, oit_heads),
791
(31, oit_atomic_counter),
792
));
793
}
794
795
if has_atmosphere
796
&& let Some(atmosphere_textures) = atmosphere_textures
797
&& let Some(atmosphere_buffer) = atmosphere_buffer.as_ref()
798
&& let Some(atmosphere_sampler) = atmosphere_sampler.as_ref()
799
&& let Some(atmosphere_buffer_binding) = atmosphere_buffer.buffer.binding()
800
{
801
entries = entries.extend_with_indices((
802
(32, &atmosphere_textures.transmittance_lut.default_view),
803
(33, &***atmosphere_sampler),
804
(34, atmosphere_buffer_binding),
805
));
806
}
807
808
if layout_key.contains(MeshPipelineViewLayoutKey::STBN) {
809
let stbn_view = &images
810
.get(&blue_noise.texture)
811
.expect("STBN texture is added unconditionally with at least a placeholder")
812
.texture_view;
813
entries = entries.extend_with_indices(((35, stbn_view),));
814
}
815
816
let mut entries_binding_array = DynamicBindGroupEntries::new();
817
818
let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get(
819
render_view_environment_maps,
820
&images,
821
&fallback_image,
822
&render_device,
823
&render_adapter,
824
);
825
match environment_map_bind_group_entries {
826
RenderViewEnvironmentMapBindGroupEntries::Single {
827
diffuse_texture_view,
828
specular_texture_view,
829
sampler,
830
} => {
831
entries_binding_array = entries_binding_array.extend_with_indices((
832
(0, diffuse_texture_view),
833
(1, specular_texture_view),
834
(2, sampler),
835
));
836
}
837
RenderViewEnvironmentMapBindGroupEntries::Multiple {
838
ref diffuse_texture_views,
839
ref specular_texture_views,
840
sampler,
841
} => {
842
entries_binding_array = entries_binding_array.extend_with_indices((
843
(0, diffuse_texture_views.as_slice()),
844
(1, specular_texture_views.as_slice()),
845
(2, sampler),
846
));
847
}
848
}
849
850
let irradiance_volume_bind_group_entries = if IRRADIANCE_VOLUMES_ARE_USABLE {
851
Some(RenderViewIrradianceVolumeBindGroupEntries::get(
852
render_view_irradiance_volumes,
853
&images,
854
&fallback_image,
855
&render_device,
856
&render_adapter,
857
))
858
} else {
859
None
860
};
861
862
match irradiance_volume_bind_group_entries {
863
Some(RenderViewIrradianceVolumeBindGroupEntries::Single {
864
texture_view,
865
sampler,
866
}) => {
867
entries_binding_array = entries_binding_array
868
.extend_with_indices(((3, texture_view), (4, sampler)));
869
}
870
Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple {
871
ref texture_views,
872
sampler,
873
}) => {
874
entries_binding_array = entries_binding_array
875
.extend_with_indices(((3, texture_views.as_slice()), (4, sampler)));
876
}
877
None => {}
878
}
879
880
let decal_bind_group_entries = RenderViewClusteredDecalBindGroupEntries::get(
881
&render_decals,
882
&decals_buffer,
883
&images,
884
&fallback_image,
885
&render_device,
886
&render_adapter,
887
);
888
889
// Add the decal bind group entries.
890
if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries {
891
entries_binding_array = entries_binding_array.extend_with_indices((
892
// `clustered_decals`
893
(
894
5,
895
render_view_decal_bind_group_entries
896
.decals
897
.as_entire_binding(),
898
),
899
// `clustered_decal_textures`
900
(
901
6,
902
render_view_decal_bind_group_entries
903
.texture_views
904
.as_slice(),
905
),
906
// `clustered_decal_sampler`
907
(7, render_view_decal_bind_group_entries.sampler),
908
));
909
}
910
911
commands.entity(entity).insert(MeshViewBindGroup {
912
main: render_device.create_bind_group(
913
"mesh_view_bind_group",
914
&pipeline_cache.get_bind_group_layout(&layout.main_layout),
915
&entries,
916
),
917
binding_array: render_device.create_bind_group(
918
"mesh_view_bind_group_binding_array",
919
&pipeline_cache.get_bind_group_layout(&layout.binding_array_layout),
920
&entries_binding_array,
921
),
922
empty: render_device.create_bind_group(
923
"mesh_view_bind_group_empty",
924
&pipeline_cache.get_bind_group_layout(&layout.empty_layout),
925
&[],
926
),
927
});
928
}
929
}
930
}
931
932