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,
47 resources::{AtmosphereBuffer, AtmosphereData, AtmosphereSampler, AtmosphereTextures},
48 EnvironmentMapUniformBuffer, ExtractedAtmosphere, FogMeta, GlobalClusterableObjectMeta,
49 GpuClusterableObjects, GpuFog, GpuLights, LightMeta, LightProbesBuffer, LightProbesUniform,
50 MeshPipeline, MeshPipelineKey, RenderViewLightProbes, ScreenSpaceAmbientOcclusionResources,
51 ScreenSpaceReflectionsBuffer, ScreenSpaceReflectionsUniform, ShadowSamplers,
52 ViewClusterBindings, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
53};
54
55#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
56use bevy_render::render_resource::binding_types::texture_cube;
57
58#[cfg(debug_assertions)]
59use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};
60
61#[derive(Clone)]
62pub struct MeshPipelineViewLayout {
63 pub main_layout: BindGroupLayoutDescriptor,
64 pub binding_array_layout: BindGroupLayoutDescriptor,
65 pub empty_layout: BindGroupLayoutDescriptor,
66
67 #[cfg(debug_assertions)]
68 pub texture_count: usize,
69}
70
71bitflags::bitflags! {
72 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
78 #[repr(transparent)]
79 pub struct MeshPipelineViewLayoutKey: u32 {
80 const MULTISAMPLED = 1 << 0;
81 const DEPTH_PREPASS = 1 << 1;
82 const NORMAL_PREPASS = 1 << 2;
83 const MOTION_VECTOR_PREPASS = 1 << 3;
84 const DEFERRED_PREPASS = 1 << 4;
85 const OIT_ENABLED = 1 << 5;
86 const ATMOSPHERE = 1 << 6;
87 }
88}
89
90impl MeshPipelineViewLayoutKey {
91 pub const COUNT: usize = Self::all().bits() as usize + 1;
93
94 pub fn label(&self) -> String {
96 use MeshPipelineViewLayoutKey as Key;
97
98 format!(
99 "mesh_view_layout{}{}{}{}{}{}{}",
100 if self.contains(Key::MULTISAMPLED) {
101 "_multisampled"
102 } else {
103 Default::default()
104 },
105 if self.contains(Key::DEPTH_PREPASS) {
106 "_depth"
107 } else {
108 Default::default()
109 },
110 if self.contains(Key::NORMAL_PREPASS) {
111 "_normal"
112 } else {
113 Default::default()
114 },
115 if self.contains(Key::MOTION_VECTOR_PREPASS) {
116 "_motion"
117 } else {
118 Default::default()
119 },
120 if self.contains(Key::DEFERRED_PREPASS) {
121 "_deferred"
122 } else {
123 Default::default()
124 },
125 if self.contains(Key::OIT_ENABLED) {
126 "_oit"
127 } else {
128 Default::default()
129 },
130 if self.contains(Key::ATMOSPHERE) {
131 "_atmosphere"
132 } else {
133 Default::default()
134 },
135 )
136 }
137}
138
139impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {
140 fn from(value: MeshPipelineKey) -> Self {
141 let mut result = MeshPipelineViewLayoutKey::empty();
142
143 if value.msaa_samples() > 1 {
144 result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
145 }
146 if value.contains(MeshPipelineKey::DEPTH_PREPASS) {
147 result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
148 }
149 if value.contains(MeshPipelineKey::NORMAL_PREPASS) {
150 result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
151 }
152 if value.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {
153 result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
154 }
155 if value.contains(MeshPipelineKey::DEFERRED_PREPASS) {
156 result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
157 }
158 if value.contains(MeshPipelineKey::OIT_ENABLED) {
159 result |= MeshPipelineViewLayoutKey::OIT_ENABLED;
160 }
161 if value.contains(MeshPipelineKey::ATMOSPHERE) {
162 result |= MeshPipelineViewLayoutKey::ATMOSPHERE;
163 }
164
165 result
166 }
167}
168
169impl From<Msaa> for MeshPipelineViewLayoutKey {
170 fn from(value: Msaa) -> Self {
171 let mut result = MeshPipelineViewLayoutKey::empty();
172
173 if value.samples() > 1 {
174 result |= MeshPipelineViewLayoutKey::MULTISAMPLED;
175 }
176
177 result
178 }
179}
180
181impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {
182 fn from(value: Option<&ViewPrepassTextures>) -> Self {
183 let mut result = MeshPipelineViewLayoutKey::empty();
184
185 if let Some(prepass_textures) = value {
186 if prepass_textures.depth.is_some() {
187 result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;
188 }
189 if prepass_textures.normal.is_some() {
190 result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;
191 }
192 if prepass_textures.motion_vectors.is_some() {
193 result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;
194 }
195 if prepass_textures.deferred.is_some() {
196 result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;
197 }
198 }
199
200 result
201 }
202}
203
204pub(crate) fn buffer_layout(
205 buffer_binding_type: BufferBindingType,
206 has_dynamic_offset: bool,
207 min_binding_size: Option<NonZero<u64>>,
208) -> BindGroupLayoutEntryBuilder {
209 match buffer_binding_type {
210 BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),
211 BufferBindingType::Storage { read_only } => {
212 if read_only {
213 storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)
214 } else {
215 storage_buffer_sized(has_dynamic_offset, min_binding_size)
216 }
217 }
218 }
219}
220
221fn layout_entries(
223 clustered_forward_buffer_binding_type: BufferBindingType,
224 visibility_ranges_buffer_binding_type: BufferBindingType,
225 layout_key: MeshPipelineViewLayoutKey,
226 render_device: &RenderDevice,
227 render_adapter: &RenderAdapter,
228) -> [Vec<BindGroupLayoutEntry>; 2] {
229 let environment_map_entries =
231 environment_map::get_bind_group_layout_entries(render_device, render_adapter);
232
233 let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(
234 ShaderStages::FRAGMENT,
235 (
236 (
238 0,
239 uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),
240 ),
241 (1, uniform_buffer::<GpuLights>(true)),
243 (
245 2,
246 #[cfg(all(
247 not(target_abi = "sim"),
248 any(
249 not(feature = "webgl"),
250 not(target_arch = "wasm32"),
251 feature = "webgpu"
252 )
253 ))]
254 texture_cube_array(TextureSampleType::Depth),
255 #[cfg(any(
256 target_abi = "sim",
257 all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))
258 ))]
259 texture_cube(TextureSampleType::Depth),
260 ),
261 (3, sampler(SamplerBindingType::Comparison)),
263 #[cfg(feature = "experimental_pbr_pcss")]
265 (4, sampler(SamplerBindingType::Filtering)),
266 (
268 5,
269 #[cfg(any(
270 not(feature = "webgl"),
271 not(target_arch = "wasm32"),
272 feature = "webgpu"
273 ))]
274 texture_2d_array(TextureSampleType::Depth),
275 #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
276 texture_2d(TextureSampleType::Depth),
277 ),
278 (6, sampler(SamplerBindingType::Comparison)),
280 #[cfg(feature = "experimental_pbr_pcss")]
282 (7, sampler(SamplerBindingType::Filtering)),
283 (
285 8,
286 buffer_layout(
287 clustered_forward_buffer_binding_type,
288 false,
289 Some(GpuClusterableObjects::min_size(
290 clustered_forward_buffer_binding_type,
291 )),
292 ),
293 ),
294 (
296 9,
297 buffer_layout(
298 clustered_forward_buffer_binding_type,
299 false,
300 Some(
301 ViewClusterBindings::min_size_clusterable_object_index_lists(
302 clustered_forward_buffer_binding_type,
303 ),
304 ),
305 ),
306 ),
307 (
309 10,
310 buffer_layout(
311 clustered_forward_buffer_binding_type,
312 false,
313 Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(
314 clustered_forward_buffer_binding_type,
315 )),
316 ),
317 ),
318 (
320 11,
321 uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
322 ),
323 (12, uniform_buffer::<GpuFog>(true)),
325 (13, uniform_buffer::<LightProbesUniform>(true)),
327 (
329 14,
330 buffer_layout(
331 visibility_ranges_buffer_binding_type,
332 false,
333 Some(Vec4::min_size()),
334 )
335 .visibility(ShaderStages::VERTEX),
336 ),
337 (15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),
339 (
341 16,
342 texture_2d(TextureSampleType::Float { filterable: false }),
343 ),
344 (17, environment_map_entries[3]),
345 ),
346 );
347
348 let tonemapping_lut_entries = get_lut_bind_group_layout_entries();
350 entries = entries.extend_with_indices((
351 (18, tonemapping_lut_entries[0]),
352 (19, tonemapping_lut_entries[1]),
353 ));
354
355 if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))
357 || (cfg!(all(feature = "webgl", target_arch = "wasm32"))
358 && !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))
359 {
360 for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)
361 .iter()
362 .zip([20, 21, 22, 23])
363 {
364 if let Some(entry) = entry {
365 entries = entries.extend_with_indices(((binding as u32, *entry),));
366 }
367 }
368 }
369
370 entries = entries.extend_with_indices((
372 (
373 24,
374 texture_2d(TextureSampleType::Float { filterable: true }),
375 ),
376 (25, sampler(SamplerBindingType::Filtering)),
377 ));
378
379 if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {
381 if is_oit_supported(render_adapter, render_device, false) {
385 entries = entries.extend_with_indices((
386 (26, storage_buffer_sized(false, None)),
388 (27, storage_buffer_sized(false, None)),
390 (
392 28,
393 uniform_buffer::<OrderIndependentTransparencySettings>(true),
394 ),
395 ));
396 }
397 }
398
399 if layout_key.contains(MeshPipelineViewLayoutKey::ATMOSPHERE) {
401 entries = entries.extend_with_indices((
402 (
404 29,
405 texture_2d(TextureSampleType::Float { filterable: true }),
406 ),
407 (30, sampler(SamplerBindingType::Filtering)),
408 (31, storage_buffer_read_only::<AtmosphereData>(false)),
410 ));
411 }
412
413 let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);
414 binding_array_entries = binding_array_entries.extend_with_indices((
415 (0, environment_map_entries[0]),
416 (1, environment_map_entries[1]),
417 (2, environment_map_entries[2]),
418 ));
419
420 if IRRADIANCE_VOLUMES_ARE_USABLE {
422 let irradiance_volume_entries =
423 irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter);
424 binding_array_entries = binding_array_entries.extend_with_indices((
425 (3, irradiance_volume_entries[0]),
426 (4, irradiance_volume_entries[1]),
427 ));
428 }
429
430 if let Some(clustered_decal_entries) =
432 decal::clustered::get_bind_group_layout_entries(render_device, render_adapter)
433 {
434 binding_array_entries = binding_array_entries.extend_with_indices((
435 (5, clustered_decal_entries[0]),
436 (6, clustered_decal_entries[1]),
437 (7, clustered_decal_entries[2]),
438 ));
439 }
440
441 [entries.to_vec(), binding_array_entries.to_vec()]
442}
443
444#[derive(Resource, Clone, Deref, DerefMut)]
449pub struct MeshPipelineViewLayouts(
450 pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,
451);
452
453impl FromWorld for MeshPipelineViewLayouts {
454 fn from_world(world: &mut World) -> Self {
455 let render_device = world.resource::<RenderDevice>();
459 let render_adapter = world.resource::<RenderAdapter>();
460
461 let clustered_forward_buffer_binding_type = render_device
462 .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
463 let visibility_ranges_buffer_binding_type = render_device
464 .get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
465
466 Self(Arc::new(array::from_fn(|i| {
467 let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);
468 let entries = layout_entries(
469 clustered_forward_buffer_binding_type,
470 visibility_ranges_buffer_binding_type,
471 key,
472 render_device,
473 render_adapter,
474 );
475 #[cfg(debug_assertions)]
476 let texture_count: usize = entries
477 .iter()
478 .flat_map(|e| {
479 e.iter()
480 .filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))
481 })
482 .count();
483
484 MeshPipelineViewLayout {
485 main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),
486 binding_array_layout: BindGroupLayoutDescriptor::new(
487 format!("{}_binding_array", key.label()),
488 &entries[1],
489 ),
490 empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),
491 #[cfg(debug_assertions)]
492 texture_count,
493 }
494 })))
495 }
496}
497
498impl MeshPipelineViewLayouts {
499 pub fn get_view_layout(
500 &self,
501 layout_key: MeshPipelineViewLayoutKey,
502 ) -> &MeshPipelineViewLayout {
503 let index = layout_key.bits() as usize;
504 let layout = &self[index];
505
506 #[cfg(debug_assertions)]
507 if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {
508 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."));
510 }
511
512 layout
513 }
514}
515
516pub fn generate_view_layouts(
519 render_device: &RenderDevice,
520 render_adapter: &RenderAdapter,
521 clustered_forward_buffer_binding_type: BufferBindingType,
522 visibility_ranges_buffer_binding_type: BufferBindingType,
523) -> [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT] {
524 array::from_fn(|i| {
525 let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);
526 let entries = layout_entries(
527 clustered_forward_buffer_binding_type,
528 visibility_ranges_buffer_binding_type,
529 key,
530 render_device,
531 render_adapter,
532 );
533
534 #[cfg(debug_assertions)]
535 let texture_count: usize = entries
536 .iter()
537 .flat_map(|e| {
538 e.iter()
539 .filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))
540 })
541 .count();
542
543 MeshPipelineViewLayout {
544 main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),
545 binding_array_layout: BindGroupLayoutDescriptor::new(
546 format!("{}_binding_array", key.label()),
547 &entries[1],
548 ),
549 empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),
550 #[cfg(debug_assertions)]
551 texture_count,
552 }
553 })
554}
555
556#[derive(Component)]
557pub struct MeshViewBindGroup {
558 pub main: BindGroup,
559 pub binding_array: BindGroup,
560 pub empty: BindGroup,
561}
562
563pub fn prepare_mesh_view_bind_groups(
564 mut commands: Commands,
565 (render_device, pipeline_cache, render_adapter): (
566 Res<RenderDevice>,
567 Res<PipelineCache>,
568 Res<RenderAdapter>,
569 ),
570 mesh_pipeline: Res<MeshPipeline>,
571 shadow_samplers: Res<ShadowSamplers>,
572 (light_meta, global_light_meta): (Res<LightMeta>, Res<GlobalClusterableObjectMeta>),
573 fog_meta: Res<FogMeta>,
574 (view_uniforms, environment_map_uniform): (Res<ViewUniforms>, Res<EnvironmentMapUniformBuffer>),
575 views: Query<(
576 Entity,
577 &ViewShadowBindings,
578 &ViewClusterBindings,
579 &Msaa,
580 Option<&ScreenSpaceAmbientOcclusionResources>,
581 Option<&ViewPrepassTextures>,
582 Option<&ViewTransmissionTexture>,
583 &Tonemapping,
584 Option<&RenderViewLightProbes<EnvironmentMapLight>>,
585 Option<&RenderViewLightProbes<IrradianceVolume>>,
586 Has<OrderIndependentTransparencySettings>,
587 Option<&AtmosphereTextures>,
588 Has<ExtractedAtmosphere>,
589 )>,
590 (images, mut fallback_images, fallback_image, fallback_image_zero): (
591 Res<RenderAssets<GpuImage>>,
592 FallbackImageMsaa,
593 Res<FallbackImage>,
594 Res<FallbackImageZero>,
595 ),
596 globals_buffer: Res<GlobalsBuffer>,
597 tonemapping_luts: Res<TonemappingLuts>,
598 light_probes_buffer: Res<LightProbesBuffer>,
599 visibility_ranges: Res<RenderVisibilityRanges>,
600 ssr_buffer: Res<ScreenSpaceReflectionsBuffer>,
601 oit_buffers: Res<OitBuffers>,
602 (decals_buffer, render_decals, atmosphere_buffer, atmosphere_sampler): (
603 Res<DecalsBuffer>,
604 Res<RenderClusteredDecals>,
605 Option<Res<AtmosphereBuffer>>,
606 Option<Res<AtmosphereSampler>>,
607 ),
608) {
609 if let (
610 Some(view_binding),
611 Some(light_binding),
612 Some(clusterable_objects_binding),
613 Some(globals),
614 Some(fog_binding),
615 Some(light_probes_binding),
616 Some(visibility_ranges_buffer),
617 Some(ssr_binding),
618 Some(environment_map_binding),
619 ) = (
620 view_uniforms.uniforms.binding(),
621 light_meta.view_gpu_lights.binding(),
622 global_light_meta.gpu_clusterable_objects.binding(),
623 globals_buffer.buffer.binding(),
624 fog_meta.gpu_fogs.binding(),
625 light_probes_buffer.binding(),
626 visibility_ranges.buffer().buffer(),
627 ssr_buffer.binding(),
628 environment_map_uniform.binding(),
629 ) {
630 for (
631 entity,
632 shadow_bindings,
633 cluster_bindings,
634 msaa,
635 ssao_resources,
636 prepass_textures,
637 transmission_texture,
638 tonemapping,
639 render_view_environment_maps,
640 render_view_irradiance_volumes,
641 has_oit,
642 atmosphere_textures,
643 has_atmosphere,
644 ) in &views
645 {
646 let fallback_ssao = fallback_images
647 .image_for_samplecount(1, TextureFormat::bevy_default())
648 .texture_view
649 .clone();
650 let ssao_view = ssao_resources
651 .map(|t| &t.screen_space_ambient_occlusion_texture.default_view)
652 .unwrap_or(&fallback_ssao);
653
654 let mut layout_key = MeshPipelineViewLayoutKey::from(*msaa)
655 | MeshPipelineViewLayoutKey::from(prepass_textures);
656 if has_oit {
657 layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;
658 }
659 if has_atmosphere {
660 layout_key |= MeshPipelineViewLayoutKey::ATMOSPHERE;
661 }
662
663 let layout = mesh_pipeline.get_view_layout(layout_key);
664
665 let mut entries = DynamicBindGroupEntries::new_with_indices((
666 (0, view_binding.clone()),
667 (1, light_binding.clone()),
668 (2, &shadow_bindings.point_light_depth_texture_view),
669 (3, &shadow_samplers.point_light_comparison_sampler),
670 #[cfg(feature = "experimental_pbr_pcss")]
671 (4, &shadow_samplers.point_light_linear_sampler),
672 (5, &shadow_bindings.directional_light_depth_texture_view),
673 (6, &shadow_samplers.directional_light_comparison_sampler),
674 #[cfg(feature = "experimental_pbr_pcss")]
675 (7, &shadow_samplers.directional_light_linear_sampler),
676 (8, clusterable_objects_binding.clone()),
677 (
678 9,
679 cluster_bindings
680 .clusterable_object_index_lists_binding()
681 .unwrap(),
682 ),
683 (10, cluster_bindings.offsets_and_counts_binding().unwrap()),
684 (11, globals.clone()),
685 (12, fog_binding.clone()),
686 (13, light_probes_binding.clone()),
687 (14, visibility_ranges_buffer.as_entire_binding()),
688 (15, ssr_binding.clone()),
689 (16, ssao_view),
690 ));
691
692 entries = entries.extend_with_indices(((17, environment_map_binding.clone()),));
693
694 let lut_bindings =
695 get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);
696 entries = entries.extend_with_indices(((18, lut_bindings.0), (19, lut_bindings.1)));
697
698 let prepass_bindings;
700 if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1
701 {
702 prepass_bindings = prepass::get_bindings(prepass_textures);
703 for (binding, index) in prepass_bindings
704 .iter()
705 .map(Option::as_ref)
706 .zip([20, 21, 22, 23])
707 .flat_map(|(b, i)| b.map(|b| (b, i)))
708 {
709 entries = entries.extend_with_indices(((index, binding),));
710 }
711 };
712
713 let transmission_view = transmission_texture
714 .map(|transmission| &transmission.view)
715 .unwrap_or(&fallback_image_zero.texture_view);
716
717 let transmission_sampler = transmission_texture
718 .map(|transmission| &transmission.sampler)
719 .unwrap_or(&fallback_image_zero.sampler);
720
721 entries =
722 entries.extend_with_indices(((24, transmission_view), (25, transmission_sampler)));
723
724 if has_oit
725 && let (
726 Some(oit_layers_binding),
727 Some(oit_layer_ids_binding),
728 Some(oit_settings_binding),
729 ) = (
730 oit_buffers.layers.binding(),
731 oit_buffers.layer_ids.binding(),
732 oit_buffers.settings.binding(),
733 )
734 {
735 entries = entries.extend_with_indices((
736 (26, oit_layers_binding.clone()),
737 (27, oit_layer_ids_binding.clone()),
738 (28, oit_settings_binding.clone()),
739 ));
740 }
741
742 if has_atmosphere
743 && let Some(atmosphere_textures) = atmosphere_textures
744 && let Some(atmosphere_buffer) = atmosphere_buffer.as_ref()
745 && let Some(atmosphere_sampler) = atmosphere_sampler.as_ref()
746 && let Some(atmosphere_buffer_binding) = atmosphere_buffer.buffer.binding()
747 {
748 entries = entries.extend_with_indices((
749 (29, &atmosphere_textures.transmittance_lut.default_view),
750 (30, &***atmosphere_sampler),
751 (31, atmosphere_buffer_binding),
752 ));
753 }
754
755 let mut entries_binding_array = DynamicBindGroupEntries::new();
756
757 let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get(
758 render_view_environment_maps,
759 &images,
760 &fallback_image,
761 &render_device,
762 &render_adapter,
763 );
764 match environment_map_bind_group_entries {
765 RenderViewEnvironmentMapBindGroupEntries::Single {
766 diffuse_texture_view,
767 specular_texture_view,
768 sampler,
769 } => {
770 entries_binding_array = entries_binding_array.extend_with_indices((
771 (0, diffuse_texture_view),
772 (1, specular_texture_view),
773 (2, sampler),
774 ));
775 }
776 RenderViewEnvironmentMapBindGroupEntries::Multiple {
777 ref diffuse_texture_views,
778 ref specular_texture_views,
779 sampler,
780 } => {
781 entries_binding_array = entries_binding_array.extend_with_indices((
782 (0, diffuse_texture_views.as_slice()),
783 (1, specular_texture_views.as_slice()),
784 (2, sampler),
785 ));
786 }
787 }
788
789 let irradiance_volume_bind_group_entries = if IRRADIANCE_VOLUMES_ARE_USABLE {
790 Some(RenderViewIrradianceVolumeBindGroupEntries::get(
791 render_view_irradiance_volumes,
792 &images,
793 &fallback_image,
794 &render_device,
795 &render_adapter,
796 ))
797 } else {
798 None
799 };
800
801 match irradiance_volume_bind_group_entries {
802 Some(RenderViewIrradianceVolumeBindGroupEntries::Single {
803 texture_view,
804 sampler,
805 }) => {
806 entries_binding_array = entries_binding_array
807 .extend_with_indices(((3, texture_view), (4, sampler)));
808 }
809 Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple {
810 ref texture_views,
811 sampler,
812 }) => {
813 entries_binding_array = entries_binding_array
814 .extend_with_indices(((3, texture_views.as_slice()), (4, sampler)));
815 }
816 None => {}
817 }
818
819 let decal_bind_group_entries = RenderViewClusteredDecalBindGroupEntries::get(
820 &render_decals,
821 &decals_buffer,
822 &images,
823 &fallback_image,
824 &render_device,
825 &render_adapter,
826 );
827
828 if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries {
830 entries_binding_array = entries_binding_array.extend_with_indices((
831 (
833 5,
834 render_view_decal_bind_group_entries
835 .decals
836 .as_entire_binding(),
837 ),
838 (
840 6,
841 render_view_decal_bind_group_entries
842 .texture_views
843 .as_slice(),
844 ),
845 (7, render_view_decal_bind_group_entries.sampler),
847 ));
848 }
849
850 commands.entity(entity).insert(MeshViewBindGroup {
851 main: render_device.create_bind_group(
852 "mesh_view_bind_group",
853 &pipeline_cache.get_bind_group_layout(&layout.main_layout),
854 &entries,
855 ),
856 binding_array: render_device.create_bind_group(
857 "mesh_view_bind_group_binding_array",
858 &pipeline_cache.get_bind_group_layout(&layout.binding_array_layout),
859 &entries_binding_array,
860 ),
861 empty: render_device.create_bind_group(
862 "mesh_view_bind_group_empty",
863 &pipeline_cache.get_bind_group_layout(&layout.empty_layout),
864 &[],
865 ),
866 });
867 }
868 }
869}