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