1use alloc::sync::Arc;
2use 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};
10use bevy_derive::{Deref, DerefMut};
11use bevy_ecs::{
12 component::Component,
13 entity::Entity,
14 query::Has,
15 resource::Resource,
16 system::{Commands, Query, Res},
17 world::{FromWorld, World},
18};
19use bevy_image::BevyDefault as _;
20use bevy_light::{EnvironmentMapLight, IrradianceVolume};
21use bevy_math::Vec4;
22use 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};
33use core::{array, num::NonZero};
34
35use 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")))]
54use bevy_render::render_resource::binding_types::texture_cube;
55
56#[cfg(debug_assertions)]
57use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};
58
59#[derive(Clone)]
60pub 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
69bitflags::bitflags! {
70 #[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
87impl MeshPipelineViewLayoutKey {
88 pub const COUNT: usize = Self::all().bits() as usize + 1;
90
91 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
131impl 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
158impl 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
170impl 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
193pub(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
210fn 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 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 (
227 0,
228 uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
229 ),
230 (1, uniform_buffer::<GpuLights>(true)),
232 (
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 (3, sampler(SamplerBindingType::Comparison)),
252 #[cfg(feature = "experimental_pbr_pcss")]
254 (4, sampler(SamplerBindingType::Filtering)),
255 (
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 (6, sampler(SamplerBindingType::Comparison)),
269 #[cfg(feature = "experimental_pbr_pcss")]
271 (7, sampler(SamplerBindingType::Filtering)),
272 (
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 (
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 (
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 (
309 11,
310 uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
311 ),
312 (12, uniform_buffer::<GpuFog>(true)),
314 (13, uniform_buffer::<LightProbesUniform>(true)),
316 (
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 (15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),
328 (
330 16,
331 texture_2d(TextureSampleType::Float { filterable: false }),
332 ),
333 (17, environment_map_entries[3]),
334 ),
335 );
336
337 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 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 entries = entries.extend_with_indices((
361 (
362 24,
363 texture_2d(TextureSampleType::Float { filterable: true }),
364 ),
365 (25, sampler(SamplerBindingType::Filtering)),
366 ));
367
368 if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {
370 if is_oit_supported(render_adapter, render_device, false) {
374 entries = entries.extend_with_indices((
375 (26, storage_buffer_sized(false, None)),
377 (27, storage_buffer_sized(false, None)),
379 (
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 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 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#[derive(Resource, Clone, Deref, DerefMut)]
424pub struct MeshPipelineViewLayouts(
425 pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,
426);
427
428impl FromWorld for MeshPipelineViewLayouts {
429 fn from_world(world: &mut World) -> Self {
430 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
475impl 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 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
493pub 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)]
535pub struct MeshViewBindGroup {
536 pub main: BindGroup,
537 pub binding_array: BindGroup,
538 pub empty: BindGroup,
539}
540
541pub 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 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 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 (
782 5,
783 render_view_decal_bind_group_entries
784 .decals
785 .as_entire_binding(),
786 ),
787 (
789 6,
790 render_view_decal_bind_group_entries
791 .texture_views
792 .as_slice(),
793 ),
794 (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}