Path: blob/main/crates/bevy_pbr/src/render/mesh_view_bindings.rs
9400 views
use alloc::sync::Arc;1use bevy_core_pipeline::{2oit::{resolve::is_oit_supported, OitBuffers, OrderIndependentTransparencySettings},3prepass::ViewPrepassTextures,4tonemapping::{5get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,6},7};8use bevy_derive::{Deref, DerefMut};9use bevy_ecs::{10component::Component,11entity::Entity,12query::Has,13resource::Resource,14system::{Commands, Query, Res},15world::{FromWorld, World},16};17use bevy_image::BevyDefault as _;18use bevy_light::{EnvironmentMapLight, IrradianceVolume};19use bevy_math::Vec4;20use bevy_render::{21globals::{GlobalsBuffer, GlobalsUniform},22render_asset::RenderAssets,23render_resource::{binding_types::*, *},24renderer::{RenderAdapter, RenderDevice},25texture::{FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage},26view::{27Msaa, RenderVisibilityRanges, ViewUniform, ViewUniforms,28VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,29},30};31use core::{array, num::NonZero};3233use crate::{34contact_shadows::{35ContactShadowsBuffer, ContactShadowsUniform, ViewContactShadowsUniformOffset,36},37decal::{38self,39clustered::{40DecalsBuffer, RenderClusteredDecals, RenderViewClusteredDecalBindGroupEntries,41},42},43environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},44irradiance_volume::{45self, RenderViewIrradianceVolumeBindGroupEntries, IRRADIANCE_VOLUMES_ARE_USABLE,46},47prepass,48resources::{AtmosphereBuffer, AtmosphereData, AtmosphereSampler, AtmosphereTextures},49Bluenoise, EnvironmentMapUniformBuffer, ExtractedAtmosphere, FogMeta,50GlobalClusterableObjectMeta, GpuClusteredLights, GpuFog, GpuLights, LightMeta,51LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes,52ScreenSpaceAmbientOcclusionResources, ScreenSpaceReflectionsBuffer,53ScreenSpaceReflectionsUniform, ShadowSamplers, ViewClusterBindings, ViewShadowBindings,54ViewTransmissionTexture, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,55};5657#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]58use bevy_render::render_resource::binding_types::texture_cube;5960#[cfg(debug_assertions)]61use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, tracing::warn};6263#[derive(Clone)]64pub struct MeshPipelineViewLayout {65pub main_layout: BindGroupLayoutDescriptor,66pub binding_array_layout: BindGroupLayoutDescriptor,67pub empty_layout: BindGroupLayoutDescriptor,6869#[cfg(debug_assertions)]70pub texture_count: usize,71}7273bitflags::bitflags! {74/// A key that uniquely identifies a [`MeshPipelineViewLayout`].75///76/// Used to generate all possible layouts for the mesh pipeline in [`generate_view_layouts`],77/// so special care must be taken to not add too many flags, as the number of possible layouts78/// will grow exponentially.79#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]80#[repr(transparent)]81pub struct MeshPipelineViewLayoutKey: u32 {82const MULTISAMPLED = 1 << 0;83const DEPTH_PREPASS = 1 << 1;84const NORMAL_PREPASS = 1 << 2;85const MOTION_VECTOR_PREPASS = 1 << 3;86const DEFERRED_PREPASS = 1 << 4;87const OIT_ENABLED = 1 << 5;88const ATMOSPHERE = 1 << 6;89const STBN = 1 << 7;90}91}9293impl MeshPipelineViewLayoutKey {94// The number of possible layouts95pub const COUNT: usize = Self::all().bits() as usize + 1;9697/// Builds a unique label for each layout based on the flags98pub fn label(&self) -> String {99use MeshPipelineViewLayoutKey as Key;100101format!(102"mesh_view_layout{}{}{}{}{}{}{}{}",103if self.contains(Key::MULTISAMPLED) {104"_multisampled"105} else {106Default::default()107},108if self.contains(Key::DEPTH_PREPASS) {109"_depth"110} else {111Default::default()112},113if self.contains(Key::NORMAL_PREPASS) {114"_normal"115} else {116Default::default()117},118if self.contains(Key::MOTION_VECTOR_PREPASS) {119"_motion"120} else {121Default::default()122},123if self.contains(Key::DEFERRED_PREPASS) {124"_deferred"125} else {126Default::default()127},128if self.contains(Key::OIT_ENABLED) {129"_oit"130} else {131Default::default()132},133if self.contains(Key::ATMOSPHERE) {134"_atmosphere"135} else {136Default::default()137},138if self.contains(Key::STBN) {139"_stbn"140} else {141Default::default()142},143)144}145}146147impl From<MeshPipelineKey> for MeshPipelineViewLayoutKey {148fn from(value: MeshPipelineKey) -> Self {149let mut result = MeshPipelineViewLayoutKey::empty();150151if value.msaa_samples() > 1 {152result |= MeshPipelineViewLayoutKey::MULTISAMPLED;153}154if value.contains(MeshPipelineKey::DEPTH_PREPASS) {155result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;156}157if value.contains(MeshPipelineKey::NORMAL_PREPASS) {158result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;159}160if value.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) {161result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;162}163if value.contains(MeshPipelineKey::DEFERRED_PREPASS) {164result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;165}166if value.contains(MeshPipelineKey::OIT_ENABLED) {167result |= MeshPipelineViewLayoutKey::OIT_ENABLED;168}169if value.contains(MeshPipelineKey::ATMOSPHERE) {170result |= MeshPipelineViewLayoutKey::ATMOSPHERE;171}172173if cfg!(feature = "bluenoise_texture") {174result |= MeshPipelineViewLayoutKey::STBN;175}176177result178}179}180181impl From<Msaa> for MeshPipelineViewLayoutKey {182fn from(value: Msaa) -> Self {183let mut result = MeshPipelineViewLayoutKey::empty();184185if value.samples() > 1 {186result |= MeshPipelineViewLayoutKey::MULTISAMPLED;187}188189result190}191}192193impl From<Option<&ViewPrepassTextures>> for MeshPipelineViewLayoutKey {194fn from(value: Option<&ViewPrepassTextures>) -> Self {195let mut result = MeshPipelineViewLayoutKey::empty();196197if let Some(prepass_textures) = value {198if prepass_textures.depth.is_some() {199result |= MeshPipelineViewLayoutKey::DEPTH_PREPASS;200}201if prepass_textures.normal.is_some() {202result |= MeshPipelineViewLayoutKey::NORMAL_PREPASS;203}204if prepass_textures.motion_vectors.is_some() {205result |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS;206}207if prepass_textures.deferred.is_some() {208result |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS;209}210}211212result213}214}215216pub(crate) fn buffer_layout(217buffer_binding_type: BufferBindingType,218has_dynamic_offset: bool,219min_binding_size: Option<NonZero<u64>>,220) -> BindGroupLayoutEntryBuilder {221match buffer_binding_type {222BufferBindingType::Uniform => uniform_buffer_sized(has_dynamic_offset, min_binding_size),223BufferBindingType::Storage { read_only } => {224if read_only {225storage_buffer_read_only_sized(has_dynamic_offset, min_binding_size)226} else {227storage_buffer_sized(has_dynamic_offset, min_binding_size)228}229}230}231}232233/// Returns the appropriate bind group layout vec based on the parameters234pub fn layout_entries(235clustered_forward_buffer_binding_type: BufferBindingType,236visibility_ranges_buffer_binding_type: BufferBindingType,237layout_key: MeshPipelineViewLayoutKey,238render_device: &RenderDevice,239render_adapter: &RenderAdapter,240) -> [Vec<BindGroupLayoutEntry>; 2] {241// EnvironmentMapLight242let environment_map_entries =243environment_map::get_bind_group_layout_entries(render_device, render_adapter);244245let mut entries = DynamicBindGroupLayoutEntries::new_with_indices(246ShaderStages::FRAGMENT,247(248// View249(2500,251uniform_buffer::<ViewUniform>(true).visibility(ShaderStages::VERTEX_FRAGMENT),252),253// Lights254(1, uniform_buffer::<GpuLights>(true)),255// Point Shadow Texture Cube Array256(2572,258#[cfg(all(259not(target_abi = "sim"),260any(261not(feature = "webgl"),262not(target_arch = "wasm32"),263feature = "webgpu"264)265))]266texture_cube_array(TextureSampleType::Depth),267#[cfg(any(268target_abi = "sim",269all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))270))]271texture_cube(TextureSampleType::Depth),272),273// Point Shadow Texture Array Comparison Sampler274(3, sampler(SamplerBindingType::Comparison)),275// Point Shadow Texture Array Linear Sampler276#[cfg(feature = "experimental_pbr_pcss")]277(4, sampler(SamplerBindingType::Filtering)),278// Directional Shadow Texture Array279(2805,281#[cfg(any(282not(feature = "webgl"),283not(target_arch = "wasm32"),284feature = "webgpu"285))]286texture_2d_array(TextureSampleType::Depth),287#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]288texture_2d(TextureSampleType::Depth),289),290// Directional Shadow Texture Array Comparison Sampler291(6, sampler(SamplerBindingType::Comparison)),292// Directional Shadow Texture Array Linear Sampler293#[cfg(feature = "experimental_pbr_pcss")]294(7, sampler(SamplerBindingType::Filtering)),295// PointLights296(2978,298buffer_layout(299clustered_forward_buffer_binding_type,300false,301Some(GpuClusteredLights::min_size(302clustered_forward_buffer_binding_type,303)),304),305),306// ClusteredLightIndexLists307(3089,309buffer_layout(310clustered_forward_buffer_binding_type,311false,312Some(313ViewClusterBindings::min_size_clusterable_object_index_lists(314clustered_forward_buffer_binding_type,315),316),317),318),319// ClusterOffsetsAndCounts320(32110,322buffer_layout(323clustered_forward_buffer_binding_type,324false,325Some(ViewClusterBindings::min_size_cluster_offsets_and_counts(326clustered_forward_buffer_binding_type,327)),328),329),330// Globals331(33211,333uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),334),335// Fog336(12, uniform_buffer::<GpuFog>(true)),337// Light probes338(13, uniform_buffer::<LightProbesUniform>(true)),339// Visibility ranges340(34114,342buffer_layout(343visibility_ranges_buffer_binding_type,344false,345Some(Vec4::min_size()),346)347.visibility(ShaderStages::VERTEX),348),349// Screen space reflection settings350(15, uniform_buffer::<ScreenSpaceReflectionsUniform>(true)),351// Contact shadows settings352(16, uniform_buffer::<ContactShadowsUniform>(true)),353// Screen space ambient occlusion texture354(35517,356texture_2d(TextureSampleType::Float { filterable: false }),357),358(18, environment_map_entries[3]),359),360);361362// Tonemapping363let tonemapping_lut_entries = get_lut_bind_group_layout_entries();364entries = entries.extend_with_indices((365(19, tonemapping_lut_entries[0]),366(20, tonemapping_lut_entries[1]),367));368369// Prepass370if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32")))371|| (cfg!(all(feature = "webgl", target_arch = "wasm32"))372&& !layout_key.contains(MeshPipelineViewLayoutKey::MULTISAMPLED))373{374for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key)375.iter()376.zip([21, 22, 23, 24])377{378if let Some(entry) = entry {379entries = entries.extend_with_indices(((binding as u32, *entry),));380}381}382}383384// View Transmission Texture385entries = entries.extend_with_indices((386(38725,388texture_2d(TextureSampleType::Float { filterable: true }),389),390(26, sampler(SamplerBindingType::Filtering)),391));392393// OIT394if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) {395// Check if we can use OIT. This is a hack to avoid errors on webgl --396// the OIT plugin will warn the user that OIT is not supported on their397// platform, so we don't need to do it here.398if is_oit_supported(render_adapter, render_device, false) {399entries = entries.extend_with_indices((400(40127,402uniform_buffer::<OrderIndependentTransparencySettings>(true),403),404// oit_nodes_capacity405(28, uniform_buffer::<u32>(false)),406// oit_nodes407(29, storage_buffer_sized(false, None)),408// oit_heads,409(30, storage_buffer_sized(false, None)),410// oit_atomic_counter411(41231,413storage_buffer_sized(false, NonZero::<u64>::new(size_of::<u32>() as u64)),414),415));416}417}418419// Atmosphere420if layout_key.contains(MeshPipelineViewLayoutKey::ATMOSPHERE) {421entries = entries.extend_with_indices((422// transmittance LUT423(42432,425texture_2d(TextureSampleType::Float { filterable: true }),426),427(33, sampler(SamplerBindingType::Filtering)),428// atmosphere data buffer429(34, storage_buffer_read_only::<AtmosphereData>(false)),430));431}432433// Blue noise434if layout_key.contains(MeshPipelineViewLayoutKey::STBN) {435entries = entries.extend_with_indices(((43635,437texture_2d_array(TextureSampleType::Float { filterable: false }),438),));439}440441let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT);442binding_array_entries = binding_array_entries.extend_with_indices((443(0, environment_map_entries[0]),444(1, environment_map_entries[1]),445(2, environment_map_entries[2]),446));447448// Irradiance volumes449if IRRADIANCE_VOLUMES_ARE_USABLE {450let irradiance_volume_entries =451irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter);452binding_array_entries = binding_array_entries.extend_with_indices((453(3, irradiance_volume_entries[0]),454(4, irradiance_volume_entries[1]),455));456}457458// Clustered decals459if let Some(clustered_decal_entries) =460decal::clustered::get_bind_group_layout_entries(render_device, render_adapter)461{462binding_array_entries = binding_array_entries.extend_with_indices((463(5, clustered_decal_entries[0]),464(6, clustered_decal_entries[1]),465(7, clustered_decal_entries[2]),466));467}468469[entries.to_vec(), binding_array_entries.to_vec()]470}471472/// Stores the view layouts for every combination of pipeline keys.473///474/// This is wrapped in an [`Arc`] so that it can be efficiently cloned and475/// placed inside specializable pipeline types.476#[derive(Resource, Clone, Deref, DerefMut)]477pub struct MeshPipelineViewLayouts(478pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,479);480481impl FromWorld for MeshPipelineViewLayouts {482fn from_world(world: &mut World) -> Self {483// Generates all possible view layouts for the mesh pipeline, based on all combinations of484// [`MeshPipelineViewLayoutKey`] flags.485486let render_device = world.resource::<RenderDevice>();487let render_adapter = world.resource::<RenderAdapter>();488489let clustered_forward_buffer_binding_type = render_device490.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);491let visibility_ranges_buffer_binding_type = render_device492.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);493494Self(Arc::new(array::from_fn(|i| {495let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);496let entries = layout_entries(497clustered_forward_buffer_binding_type,498visibility_ranges_buffer_binding_type,499key,500render_device,501render_adapter,502);503#[cfg(debug_assertions)]504let texture_count: usize = entries505.iter()506.flat_map(|e| {507e.iter()508.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))509})510.count();511512MeshPipelineViewLayout {513main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),514binding_array_layout: BindGroupLayoutDescriptor::new(515format!("{}_binding_array", key.label()),516&entries[1],517),518empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),519#[cfg(debug_assertions)]520texture_count,521}522})))523}524}525526impl MeshPipelineViewLayouts {527pub fn get_view_layout(528&self,529layout_key: MeshPipelineViewLayoutKey,530) -> &MeshPipelineViewLayout {531let index = layout_key.bits() as usize;532let layout = &self[index];533534#[cfg(debug_assertions)]535if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {536// Issue our own warning here because Naga's error message is a bit cryptic in this situation537once!(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."));538}539540layout541}542}543544/// Generates all possible view layouts for the mesh pipeline, based on all combinations of545/// [`MeshPipelineViewLayoutKey`] flags.546#[deprecated(since = "0.16.0", note = "Use `layout_entries` instead")]547pub fn generate_view_layouts(548render_device: &RenderDevice,549render_adapter: &RenderAdapter,550clustered_forward_buffer_binding_type: BufferBindingType,551visibility_ranges_buffer_binding_type: BufferBindingType,552) -> [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT] {553array::from_fn(|i| {554let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);555let entries = layout_entries(556clustered_forward_buffer_binding_type,557visibility_ranges_buffer_binding_type,558key,559render_device,560render_adapter,561);562563#[cfg(debug_assertions)]564let texture_count: usize = entries565.iter()566.flat_map(|e| {567e.iter()568.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))569})570.count();571572MeshPipelineViewLayout {573main_layout: BindGroupLayoutDescriptor::new(key.label(), &entries[0]),574binding_array_layout: BindGroupLayoutDescriptor::new(575format!("{}_binding_array", key.label()),576&entries[1],577),578empty_layout: BindGroupLayoutDescriptor::new(format!("{}_empty", key.label()), &[]),579#[cfg(debug_assertions)]580texture_count,581}582})583}584585#[derive(Component)]586pub struct MeshViewBindGroup {587pub main: BindGroup,588pub binding_array: BindGroup,589pub empty: BindGroup,590}591592pub fn prepare_mesh_view_bind_groups(593mut commands: Commands,594(render_device, pipeline_cache, render_adapter): (595Res<RenderDevice>,596Res<PipelineCache>,597Res<RenderAdapter>,598),599mesh_pipeline: Res<MeshPipeline>,600shadow_samplers: Res<ShadowSamplers>,601(light_meta, global_clusterable_object_meta): (602Res<LightMeta>,603Res<GlobalClusterableObjectMeta>,604),605fog_meta: Res<FogMeta>,606(view_uniforms, environment_map_uniform): (Res<ViewUniforms>, Res<EnvironmentMapUniformBuffer>),607views: Query<(608Entity,609&ViewShadowBindings,610&ViewClusterBindings,611&Msaa,612Option<&ScreenSpaceAmbientOcclusionResources>,613Option<&ViewPrepassTextures>,614Option<&ViewTransmissionTexture>,615&Tonemapping,616Option<&RenderViewLightProbes<EnvironmentMapLight>>,617Option<&RenderViewLightProbes<IrradianceVolume>>,618Has<OrderIndependentTransparencySettings>,619Option<&AtmosphereTextures>,620Has<ExtractedAtmosphere>,621Option<&ViewContactShadowsUniformOffset>,622)>,623(images, mut fallback_images, fallback_image, fallback_image_zero): (624Res<RenderAssets<GpuImage>>,625FallbackImageMsaa,626Res<FallbackImage>,627Res<FallbackImageZero>,628),629globals_buffer: Res<GlobalsBuffer>,630tonemapping_luts: Res<TonemappingLuts>,631light_probes_buffer: Res<LightProbesBuffer>,632visibility_ranges: Res<RenderVisibilityRanges>,633(ssr_buffer, contact_shadows_buffer): (634Res<ScreenSpaceReflectionsBuffer>,635Res<ContactShadowsBuffer>,636),637oit_buffers: Res<OitBuffers>,638(decals_buffer, render_decals, atmosphere_buffer, atmosphere_sampler, blue_noise): (639Res<DecalsBuffer>,640Res<RenderClusteredDecals>,641Option<Res<AtmosphereBuffer>>,642Option<Res<AtmosphereSampler>>,643Res<Bluenoise>,644),645) {646if let (647Some(view_binding),648Some(light_binding),649Some(clusterable_objects_binding),650Some(globals),651Some(fog_binding),652Some(light_probes_binding),653Some(visibility_ranges_buffer),654Some(ssr_binding),655Some(contact_shadows_binding),656Some(environment_map_binding),657) = (658view_uniforms.uniforms.binding(),659light_meta.view_gpu_lights.binding(),660global_clusterable_object_meta661.gpu_clustered_lights662.binding(),663globals_buffer.buffer.binding(),664fog_meta.gpu_fogs.binding(),665light_probes_buffer.binding(),666visibility_ranges.buffer().buffer(),667ssr_buffer.binding(),668contact_shadows_buffer.0.binding(),669environment_map_uniform.binding(),670) {671for (672entity,673shadow_bindings,674cluster_bindings,675msaa,676ssao_resources,677prepass_textures,678transmission_texture,679tonemapping,680render_view_environment_maps,681render_view_irradiance_volumes,682has_oit,683atmosphere_textures,684has_atmosphere,685_contact_shadows_offset,686) in &views687{688let fallback_ssao = fallback_images689.image_for_samplecount(1, TextureFormat::bevy_default())690.texture_view691.clone();692let ssao_view = ssao_resources693.map(|t| &t.screen_space_ambient_occlusion_texture.default_view)694.unwrap_or(&fallback_ssao);695696let mut layout_key = MeshPipelineViewLayoutKey::from(*msaa)697| MeshPipelineViewLayoutKey::from(prepass_textures);698if has_oit {699layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;700}701if has_atmosphere {702layout_key |= MeshPipelineViewLayoutKey::ATMOSPHERE;703}704if cfg!(feature = "bluenoise_texture") {705layout_key |= MeshPipelineViewLayoutKey::STBN;706}707708let layout = mesh_pipeline.get_view_layout(layout_key);709710let mut entries = DynamicBindGroupEntries::new_with_indices((711(0, view_binding.clone()),712(1, light_binding.clone()),713(2, &shadow_bindings.point_light_depth_texture_view),714(3, &shadow_samplers.point_light_comparison_sampler),715#[cfg(feature = "experimental_pbr_pcss")]716(4, &shadow_samplers.point_light_linear_sampler),717(5, &shadow_bindings.directional_light_depth_texture_view),718(6, &shadow_samplers.directional_light_comparison_sampler),719#[cfg(feature = "experimental_pbr_pcss")]720(7, &shadow_samplers.directional_light_linear_sampler),721(8, clusterable_objects_binding.clone()),722(7239,724cluster_bindings725.clusterable_object_index_lists_binding()726.unwrap(),727),728(10, cluster_bindings.offsets_and_counts_binding().unwrap()),729(11, globals.clone()),730(12, fog_binding.clone()),731(13, light_probes_binding.clone()),732(14, visibility_ranges_buffer.as_entire_binding()),733(15, ssr_binding.clone()),734(16, contact_shadows_binding.clone()),735(17, ssao_view),736));737738entries = entries.extend_with_indices(((18, environment_map_binding.clone()),));739740let lut_bindings =741get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);742entries = entries.extend_with_indices(((19, lut_bindings.0), (20, lut_bindings.1)));743744// When using WebGL, we can't have a depth texture with multisampling745let prepass_bindings;746if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1747{748prepass_bindings = prepass::get_bindings(prepass_textures);749for (binding, index) in prepass_bindings750.iter()751.map(Option::as_ref)752.zip([21, 22, 23, 24])753.flat_map(|(b, i)| b.map(|b| (b, i)))754{755entries = entries.extend_with_indices(((index, binding),));756}757};758759let transmission_view = transmission_texture760.map(|transmission| &transmission.view)761.unwrap_or(&fallback_image_zero.texture_view);762763let transmission_sampler = transmission_texture764.map(|transmission| &transmission.sampler)765.unwrap_or(&fallback_image_zero.sampler);766767entries =768entries.extend_with_indices(((25, transmission_view), (26, transmission_sampler)));769770if has_oit771&& let (772Some(oit_settings_binding),773Some(oit_nodes_capacity),774Some(oit_nodes),775Some(oit_heads),776Some(oit_atomic_counter),777) = (778oit_buffers.settings.binding(),779oit_buffers.nodes_capacity.binding(),780oit_buffers.nodes.binding(),781oit_buffers.heads.binding(),782oit_buffers.atomic_counter.binding(),783)784{785entries = entries.extend_with_indices((786(27, oit_settings_binding),787(28, oit_nodes_capacity),788(29, oit_nodes),789(30, oit_heads),790(31, oit_atomic_counter),791));792}793794if has_atmosphere795&& let Some(atmosphere_textures) = atmosphere_textures796&& let Some(atmosphere_buffer) = atmosphere_buffer.as_ref()797&& let Some(atmosphere_sampler) = atmosphere_sampler.as_ref()798&& let Some(atmosphere_buffer_binding) = atmosphere_buffer.buffer.binding()799{800entries = entries.extend_with_indices((801(32, &atmosphere_textures.transmittance_lut.default_view),802(33, &***atmosphere_sampler),803(34, atmosphere_buffer_binding),804));805}806807if layout_key.contains(MeshPipelineViewLayoutKey::STBN) {808let stbn_view = &images809.get(&blue_noise.texture)810.expect("STBN texture is added unconditionally with at least a placeholder")811.texture_view;812entries = entries.extend_with_indices(((35, stbn_view),));813}814815let mut entries_binding_array = DynamicBindGroupEntries::new();816817let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get(818render_view_environment_maps,819&images,820&fallback_image,821&render_device,822&render_adapter,823);824match environment_map_bind_group_entries {825RenderViewEnvironmentMapBindGroupEntries::Single {826diffuse_texture_view,827specular_texture_view,828sampler,829} => {830entries_binding_array = entries_binding_array.extend_with_indices((831(0, diffuse_texture_view),832(1, specular_texture_view),833(2, sampler),834));835}836RenderViewEnvironmentMapBindGroupEntries::Multiple {837ref diffuse_texture_views,838ref specular_texture_views,839sampler,840} => {841entries_binding_array = entries_binding_array.extend_with_indices((842(0, diffuse_texture_views.as_slice()),843(1, specular_texture_views.as_slice()),844(2, sampler),845));846}847}848849let irradiance_volume_bind_group_entries = if IRRADIANCE_VOLUMES_ARE_USABLE {850Some(RenderViewIrradianceVolumeBindGroupEntries::get(851render_view_irradiance_volumes,852&images,853&fallback_image,854&render_device,855&render_adapter,856))857} else {858None859};860861match irradiance_volume_bind_group_entries {862Some(RenderViewIrradianceVolumeBindGroupEntries::Single {863texture_view,864sampler,865}) => {866entries_binding_array = entries_binding_array867.extend_with_indices(((3, texture_view), (4, sampler)));868}869Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple {870ref texture_views,871sampler,872}) => {873entries_binding_array = entries_binding_array874.extend_with_indices(((3, texture_views.as_slice()), (4, sampler)));875}876None => {}877}878879let decal_bind_group_entries = RenderViewClusteredDecalBindGroupEntries::get(880&render_decals,881&decals_buffer,882&images,883&fallback_image,884&render_device,885&render_adapter,886);887888// Add the decal bind group entries.889if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries {890entries_binding_array = entries_binding_array.extend_with_indices((891// `clustered_decals`892(8935,894render_view_decal_bind_group_entries895.decals896.as_entire_binding(),897),898// `clustered_decal_textures`899(9006,901render_view_decal_bind_group_entries902.texture_views903.as_slice(),904),905// `clustered_decal_sampler`906(7, render_view_decal_bind_group_entries.sampler),907));908}909910commands.entity(entity).insert(MeshViewBindGroup {911main: render_device.create_bind_group(912"mesh_view_bind_group",913&pipeline_cache.get_bind_group_layout(&layout.main_layout),914&entries,915),916binding_array: render_device.create_bind_group(917"mesh_view_bind_group_binding_array",918&pipeline_cache.get_bind_group_layout(&layout.binding_array_layout),919&entries_binding_array,920),921empty: render_device.create_bind_group(922"mesh_view_bind_group_empty",923&pipeline_cache.get_bind_group_layout(&layout.empty_layout),924&[],925),926});927}928}929}930931932