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