Skip to main content

bevy_pbr/render/
mesh_bindings.rs

1//! Bind group layout related definitions for the mesh pipeline.
2
3use arrayvec::ArrayVec;
4use bevy_math::Mat4;
5use bevy_mesh::morph::MAX_MORPH_WEIGHTS;
6use bevy_render::{
7    mesh::morph::MorphTargetsResource,
8    render_resource::*,
9    renderer::{RenderAdapter, RenderDevice},
10};
11
12use crate::{binding_arrays_are_usable, render::skin::MAX_JOINTS, skin, LightmapSlab};
13
14const MORPH_WEIGHT_SIZE: usize = size_of::<f32>();
15
16/// This is used to allocate buffers.
17/// The correctness of the value depends on the GPU/platform.
18/// The current value is chosen because it is guaranteed to work everywhere.
19/// To allow for bigger values, a check must be made for the limits
20/// of the GPU at runtime, which would mean not using consts anymore.
21pub const MORPH_BUFFER_SIZE: usize = MAX_MORPH_WEIGHTS * MORPH_WEIGHT_SIZE;
22
23const JOINT_SIZE: usize = size_of::<Mat4>();
24pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;
25
26/// Individual layout entries.
27mod layout_entry {
28    use core::num::NonZeroU32;
29
30    use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
31    use crate::{render::skin, GpuMorphDescriptor, MeshUniform, LIGHTMAPS_PER_SLAB};
32    use bevy_mesh::morph::MorphAttributes;
33    use bevy_render::{
34        render_resource::{
35            binding_types::{
36                sampler, storage_buffer_read_only, storage_buffer_read_only_sized, texture_2d,
37                texture_3d, uniform_buffer_sized,
38            },
39            BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, SamplerBindingType,
40            ShaderStages, TextureSampleType,
41        },
42        settings::WgpuLimits,
43    };
44
45    pub(super) fn model(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
46        GpuArrayBuffer::<MeshUniform>::binding_layout(limits)
47            .visibility(ShaderStages::VERTEX_FRAGMENT)
48    }
49    pub(super) fn skinning(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
50        // If we can use storage buffers, do so. Otherwise, fall back to uniform
51        // buffers.
52        let size = BufferSize::new(JOINT_BUFFER_SIZE as u64);
53        if skin::skins_use_uniform_buffers(limits) {
54            uniform_buffer_sized(true, size)
55        } else {
56            storage_buffer_read_only_sized(false, size)
57        }
58    }
59    pub(super) fn weights(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
60        if skin::skins_use_uniform_buffers(limits) {
61            uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
62        } else {
63            storage_buffer_read_only::<f32>(false)
64        }
65    }
66    pub(super) fn targets(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
67        if skin::skins_use_uniform_buffers(limits) {
68            texture_3d(TextureSampleType::Float { filterable: false })
69        } else {
70            storage_buffer_read_only::<MorphAttributes>(false)
71        }
72    }
73    pub(super) fn morph_descriptors() -> BindGroupLayoutEntryBuilder {
74        storage_buffer_read_only::<GpuMorphDescriptor>(false)
75    }
76    pub(super) fn lightmaps_texture_view() -> BindGroupLayoutEntryBuilder {
77        texture_2d(TextureSampleType::Float { filterable: true }).visibility(ShaderStages::FRAGMENT)
78    }
79    pub(super) fn lightmaps_sampler() -> BindGroupLayoutEntryBuilder {
80        sampler(SamplerBindingType::Filtering).visibility(ShaderStages::FRAGMENT)
81    }
82    pub(super) fn lightmaps_texture_view_array() -> BindGroupLayoutEntryBuilder {
83        texture_2d(TextureSampleType::Float { filterable: true })
84            .visibility(ShaderStages::FRAGMENT)
85            .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
86    }
87    pub(super) fn lightmaps_sampler_array() -> BindGroupLayoutEntryBuilder {
88        sampler(SamplerBindingType::Filtering)
89            .visibility(ShaderStages::FRAGMENT)
90            .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
91    }
92}
93
94/// Individual [`BindGroupEntry`]
95/// for bind groups.
96mod entry {
97    use crate::render::skin;
98    use bevy_render::mesh::morph::MorphTargetsResource;
99
100    use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
101    use bevy_render::{
102        render_resource::{
103            BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, Sampler,
104            TextureView, WgpuSampler, WgpuTextureView,
105        },
106        renderer::RenderDevice,
107    };
108
109    fn entry(binding: u32, size: Option<u64>, buffer: &Buffer) -> BindGroupEntry<'_> {
110        BindGroupEntry {
111            binding,
112            resource: BindingResource::Buffer(BufferBinding {
113                buffer,
114                offset: 0,
115                size: size.map(|size| BufferSize::new(size).unwrap()),
116            }),
117        }
118    }
119    pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {
120        BindGroupEntry { binding, resource }
121    }
122    pub(super) fn skinning<'a>(
123        render_device: &RenderDevice,
124        binding: u32,
125        buffer: &'a Buffer,
126    ) -> BindGroupEntry<'a> {
127        let size = if skin::skins_use_uniform_buffers(&render_device.limits()) {
128            Some(JOINT_BUFFER_SIZE as u64)
129        } else {
130            None
131        };
132        entry(binding, size, buffer)
133    }
134    pub(super) fn weights<'a>(
135        render_device: &'_ RenderDevice,
136        binding: u32,
137        buffer: &'a Buffer,
138    ) -> BindGroupEntry<'a> {
139        if skin::skins_use_uniform_buffers(&render_device.limits()) {
140            entry(binding, Some(MORPH_BUFFER_SIZE as u64), buffer)
141        } else {
142            entry(binding, None, buffer)
143        }
144    }
145    pub(super) fn targets(binding: u32, targets: MorphTargetsResource<'_>) -> BindGroupEntry<'_> {
146        BindGroupEntry {
147            binding,
148            resource: match targets {
149                MorphTargetsResource::Texture(texture_view) => {
150                    BindingResource::TextureView(texture_view)
151                }
152                MorphTargetsResource::Storage(buffer) => buffer.as_entire_binding(),
153            },
154        }
155    }
156    pub(super) fn morph_descriptors(binding: u32, buffer: &Buffer) -> BindGroupEntry<'_> {
157        entry(binding, None, buffer)
158    }
159    pub(super) fn lightmaps_texture_view(
160        binding: u32,
161        texture: &TextureView,
162    ) -> BindGroupEntry<'_> {
163        BindGroupEntry {
164            binding,
165            resource: BindingResource::TextureView(texture),
166        }
167    }
168    pub(super) fn lightmaps_sampler(binding: u32, sampler: &Sampler) -> BindGroupEntry<'_> {
169        BindGroupEntry {
170            binding,
171            resource: BindingResource::Sampler(sampler),
172        }
173    }
174    pub(super) fn lightmaps_texture_view_array<'a>(
175        binding: u32,
176        textures: &'a [&'a WgpuTextureView],
177    ) -> BindGroupEntry<'a> {
178        BindGroupEntry {
179            binding,
180            resource: BindingResource::TextureViewArray(textures),
181        }
182    }
183    pub(super) fn lightmaps_sampler_array<'a>(
184        binding: u32,
185        samplers: &'a [&'a WgpuSampler],
186    ) -> BindGroupEntry<'a> {
187        BindGroupEntry {
188            binding,
189            resource: BindingResource::SamplerArray(samplers),
190        }
191    }
192}
193
194/// All possible [`BindGroupLayout`]s in bevy's default mesh shader (`mesh.wgsl`).
195#[derive(Clone)]
196pub struct MeshLayouts {
197    /// The mesh model uniform (transform) and nothing else.
198    pub model_only: BindGroupLayoutDescriptor,
199
200    /// Includes the lightmap texture and uniform.
201    pub lightmapped: BindGroupLayoutDescriptor,
202
203    /// Also includes the uniform for skinning
204    pub skinned: BindGroupLayoutDescriptor,
205
206    /// Like [`MeshLayouts::skinned`], but includes slots for the previous
207    /// frame's joint matrices, so that we can compute motion vectors.
208    pub skinned_motion: BindGroupLayoutDescriptor,
209
210    /// Also includes the uniform and [`MorphAttributes`] for morph targets.
211    ///
212    /// [`MorphAttributes`]: bevy_mesh::morph::MorphAttributes
213    pub morphed: BindGroupLayoutDescriptor,
214
215    /// Like [`MeshLayouts::morphed`], but includes a slot for the previous
216    /// frame's morph weights, so that we can compute motion vectors.
217    pub morphed_motion: BindGroupLayoutDescriptor,
218
219    /// Also includes both uniforms for skinning and morph targets, also the
220    /// morph target [`MorphAttributes`] binding.
221    ///
222    /// [`MorphAttributes`]: bevy_mesh::morph::MorphAttributes
223    pub morphed_skinned: BindGroupLayoutDescriptor,
224
225    /// Like [`MeshLayouts::morphed_skinned`], but includes slots for the
226    /// previous frame's joint matrices and morph weights, so that we can
227    /// compute motion vectors.
228    pub morphed_skinned_motion: BindGroupLayoutDescriptor,
229}
230
231impl MeshLayouts {
232    /// Prepare the layouts used by the default bevy [`Mesh`].
233    ///
234    /// [`Mesh`]: bevy_mesh::Mesh
235    pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
236        MeshLayouts {
237            model_only: Self::model_only_layout(render_device),
238            lightmapped: Self::lightmapped_layout(render_device, render_adapter),
239            skinned: Self::skinned_layout(render_device),
240            skinned_motion: Self::skinned_motion_layout(render_device),
241            morphed: Self::morphed_layout(render_device),
242            morphed_motion: Self::morphed_motion_layout(render_device),
243            morphed_skinned: Self::morphed_skinned_layout(render_device),
244            morphed_skinned_motion: Self::morphed_skinned_motion_layout(render_device),
245        }
246    }
247
248    // ---------- create individual BindGroupLayouts ----------
249
250    fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
251        BindGroupLayoutDescriptor::new(
252            "mesh_layout",
253            &BindGroupLayoutEntries::single(
254                ShaderStages::empty(),
255                layout_entry::model(&render_device.limits()),
256            ),
257        )
258    }
259
260    /// Creates the layout for skinned meshes.
261    fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
262        BindGroupLayoutDescriptor::new(
263            "skinned_mesh_layout",
264            &BindGroupLayoutEntries::with_indices(
265                ShaderStages::VERTEX,
266                (
267                    (0, layout_entry::model(&render_device.limits())),
268                    // The current frame's joint matrix buffer.
269                    (1, layout_entry::skinning(&render_device.limits())),
270                ),
271            ),
272        )
273    }
274
275    /// Creates the layout for skinned meshes with the infrastructure to compute
276    /// motion vectors.
277    fn skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
278        BindGroupLayoutDescriptor::new(
279            "skinned_motion_mesh_layout",
280            &BindGroupLayoutEntries::with_indices(
281                ShaderStages::VERTEX,
282                (
283                    (0, layout_entry::model(&render_device.limits())),
284                    // The current frame's joint matrix buffer.
285                    (1, layout_entry::skinning(&render_device.limits())),
286                    // The previous frame's joint matrix buffer.
287                    (6, layout_entry::skinning(&render_device.limits())),
288                ),
289            ),
290        )
291    }
292
293    /// Creates the layout for meshes with morph targets.
294    fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
295        let limits = render_device.limits();
296
297        let mut entries: ArrayVec<BindGroupLayoutEntry, 4> = ArrayVec::new();
298
299        entries.extend(
300            [
301                (0, layout_entry::model(&limits)),
302                // The current frame's morph weight buffer.
303                (2, layout_entry::weights(&limits)),
304                (3, layout_entry::targets(&limits)),
305            ]
306            .iter()
307            .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
308        );
309
310        if !skin::skins_use_uniform_buffers(&render_device.limits()) {
311            entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
312        }
313
314        BindGroupLayoutDescriptor::new("morphed_mesh_layout", &entries)
315    }
316
317    /// Creates the layout for meshes with morph targets and the infrastructure
318    /// to compute motion vectors.
319    fn morphed_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
320        let limits = render_device.limits();
321
322        let mut entries: ArrayVec<BindGroupLayoutEntry, 5> = ArrayVec::new();
323
324        entries.extend(
325            [
326                (0, layout_entry::model(&limits)),
327                // The current frame's morph weight buffer.
328                (2, layout_entry::weights(&limits)),
329                (3, layout_entry::targets(&limits)),
330                // The previous frame's morph weight buffer.
331                (7, layout_entry::weights(&limits)),
332            ]
333            .iter()
334            .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
335        );
336
337        if !skin::skins_use_uniform_buffers(&render_device.limits()) {
338            entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
339        }
340
341        BindGroupLayoutDescriptor::new("morphed_motion_layout", &entries)
342    }
343
344    /// Creates the bind group layout for meshes with both skins and morph
345    /// targets.
346    fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
347        let limits = render_device.limits();
348
349        let mut entries: ArrayVec<BindGroupLayoutEntry, 5> = ArrayVec::new();
350
351        entries.extend(
352            [
353                (0, layout_entry::model(&limits)),
354                // The current frame's joint matrix buffer.
355                (1, layout_entry::skinning(&limits)),
356                // The current frame's morph weight buffer.
357                (2, layout_entry::weights(&limits)),
358                (3, layout_entry::targets(&limits)),
359            ]
360            .iter()
361            .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
362        );
363
364        if !skin::skins_use_uniform_buffers(&render_device.limits()) {
365            entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
366        }
367
368        BindGroupLayoutDescriptor::new("morphed_skinned_mesh_layout", &entries)
369    }
370
371    /// Creates the bind group layout for meshes with both skins and morph
372    /// targets, in addition to the infrastructure to compute motion vectors.
373    fn morphed_skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
374        let limits = render_device.limits();
375
376        let mut entries: ArrayVec<BindGroupLayoutEntry, 7> = ArrayVec::new();
377
378        entries.extend(
379            [
380                (0, layout_entry::model(&limits)),
381                // The current frame's joint matrix buffer.
382                (1, layout_entry::skinning(&limits)),
383                // The current frame's morph weight buffer.
384                (2, layout_entry::weights(&limits)),
385                (3, layout_entry::targets(&limits)),
386                // The previous frame's joint matrix buffer.
387                (6, layout_entry::skinning(&limits)),
388                // The previous frame's morph weight buffer.
389                (7, layout_entry::weights(&limits)),
390            ]
391            .iter()
392            .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
393        );
394
395        if !skin::skins_use_uniform_buffers(&render_device.limits()) {
396            entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
397        }
398
399        BindGroupLayoutDescriptor::new("morphed_skinned_motion_mesh_layout", &entries)
400    }
401
402    fn lightmapped_layout(
403        render_device: &RenderDevice,
404        render_adapter: &RenderAdapter,
405    ) -> BindGroupLayoutDescriptor {
406        if binding_arrays_are_usable(render_device, render_adapter) {
407            BindGroupLayoutDescriptor::new(
408                "lightmapped_mesh_layout",
409                &BindGroupLayoutEntries::with_indices(
410                    ShaderStages::VERTEX,
411                    (
412                        (0, layout_entry::model(&render_device.limits())),
413                        (4, layout_entry::lightmaps_texture_view_array()),
414                        (5, layout_entry::lightmaps_sampler_array()),
415                    ),
416                ),
417            )
418        } else {
419            BindGroupLayoutDescriptor::new(
420                "lightmapped_mesh_layout",
421                &BindGroupLayoutEntries::with_indices(
422                    ShaderStages::VERTEX,
423                    (
424                        (0, layout_entry::model(&render_device.limits())),
425                        (4, layout_entry::lightmaps_texture_view()),
426                        (5, layout_entry::lightmaps_sampler()),
427                    ),
428                ),
429            )
430        }
431    }
432
433    // ---------- BindGroup methods ----------
434
435    pub fn model_only(
436        &self,
437        render_device: &RenderDevice,
438        pipeline_cache: &PipelineCache,
439        model: &BindingResource,
440    ) -> BindGroup {
441        render_device.create_bind_group(
442            "model_only_mesh_bind_group",
443            &pipeline_cache.get_bind_group_layout(&self.model_only),
444            &[entry::model(0, model.clone())],
445        )
446    }
447
448    pub fn lightmapped(
449        &self,
450        render_device: &RenderDevice,
451        pipeline_cache: &PipelineCache,
452        model: &BindingResource,
453        lightmap_slab: &LightmapSlab,
454        bindless_lightmaps: bool,
455    ) -> BindGroup {
456        if bindless_lightmaps {
457            let (texture_views, samplers) = lightmap_slab.build_binding_arrays();
458            render_device.create_bind_group(
459                "lightmapped_mesh_bind_group",
460                &pipeline_cache.get_bind_group_layout(&self.lightmapped),
461                &[
462                    entry::model(0, model.clone()),
463                    entry::lightmaps_texture_view_array(4, &texture_views),
464                    entry::lightmaps_sampler_array(5, &samplers),
465                ],
466            )
467        } else {
468            let (texture_view, sampler) = lightmap_slab.bindings_for_first_lightmap();
469            render_device.create_bind_group(
470                "lightmapped_mesh_bind_group",
471                &pipeline_cache.get_bind_group_layout(&self.lightmapped),
472                &[
473                    entry::model(0, model.clone()),
474                    entry::lightmaps_texture_view(4, texture_view),
475                    entry::lightmaps_sampler(5, sampler),
476                ],
477            )
478        }
479    }
480
481    /// Creates the bind group for skinned meshes with no morph targets.
482    pub fn skinned(
483        &self,
484        render_device: &RenderDevice,
485        pipeline_cache: &PipelineCache,
486        model: &BindingResource,
487        current_skin: &Buffer,
488    ) -> BindGroup {
489        render_device.create_bind_group(
490            "skinned_mesh_bind_group",
491            &pipeline_cache.get_bind_group_layout(&self.skinned),
492            &[
493                entry::model(0, model.clone()),
494                entry::skinning(render_device, 1, current_skin),
495            ],
496        )
497    }
498
499    /// Creates the bind group for skinned meshes with no morph targets, with
500    /// the infrastructure to compute motion vectors.
501    ///
502    /// `current_skin` is the buffer of joint matrices for this frame;
503    /// `prev_skin` is the buffer for the previous frame. The latter is used for
504    /// motion vector computation. If there is no such applicable buffer,
505    /// `current_skin` and `prev_skin` will reference the same buffer.
506    pub fn skinned_motion(
507        &self,
508        render_device: &RenderDevice,
509        pipeline_cache: &PipelineCache,
510        model: &BindingResource,
511        current_skin: &Buffer,
512        prev_skin: &Buffer,
513    ) -> BindGroup {
514        render_device.create_bind_group(
515            "skinned_motion_mesh_bind_group",
516            &pipeline_cache.get_bind_group_layout(&self.skinned_motion),
517            &[
518                entry::model(0, model.clone()),
519                entry::skinning(render_device, 1, current_skin),
520                entry::skinning(render_device, 6, prev_skin),
521            ],
522        )
523    }
524
525    /// Creates the bind group for meshes with no skins but morph targets.
526    pub fn morphed(
527        &self,
528        render_device: &RenderDevice,
529        pipeline_cache: &PipelineCache,
530        model: &BindingResource,
531        current_weights: &Buffer,
532        targets: MorphTargetsResource,
533        maybe_morph_descriptors: Option<&Buffer>,
534    ) -> BindGroup {
535        let mut entries: ArrayVec<BindGroupEntry, 4> = ArrayVec::new();
536
537        entries.extend([
538            entry::model(0, model.clone()),
539            entry::weights(render_device, 2, current_weights),
540            entry::targets(3, targets),
541        ]);
542
543        if let Some(morph_descriptors) = maybe_morph_descriptors {
544            entries.push(entry::morph_descriptors(8, morph_descriptors));
545        }
546
547        render_device.create_bind_group(
548            "morphed_mesh_bind_group",
549            &pipeline_cache.get_bind_group_layout(&self.morphed),
550            &entries,
551        )
552    }
553
554    /// Creates the bind group for meshes with no skins but morph targets, in
555    /// addition to the infrastructure to compute motion vectors.
556    ///
557    /// `current_weights` is the buffer of morph weights for this frame;
558    /// `prev_weights` is the buffer for the previous frame. The latter is used
559    /// for motion vector computation. If there is no such applicable buffer,
560    /// `current_weights` and `prev_weights` will reference the same buffer.
561    pub fn morphed_motion(
562        &self,
563        render_device: &RenderDevice,
564        pipeline_cache: &PipelineCache,
565        model: &BindingResource,
566        current_weights: &Buffer,
567        prev_weights: &Buffer,
568        targets: MorphTargetsResource,
569        maybe_morph_descriptors: Option<&Buffer>,
570    ) -> BindGroup {
571        let mut entries: ArrayVec<BindGroupEntry, 5> = ArrayVec::new();
572
573        entries.extend([
574            entry::model(0, model.clone()),
575            entry::weights(render_device, 2, current_weights),
576            entry::targets(3, targets),
577            entry::weights(render_device, 7, prev_weights),
578        ]);
579
580        if let Some(morph_descriptors) = maybe_morph_descriptors {
581            entries.push(entry::morph_descriptors(8, morph_descriptors));
582        }
583
584        render_device.create_bind_group(
585            "morphed_motion_mesh_bind_group",
586            &pipeline_cache.get_bind_group_layout(&self.morphed_motion),
587            &entries,
588        )
589    }
590
591    /// Creates the bind group for meshes with skins and morph targets.
592    pub fn morphed_skinned(
593        &self,
594        render_device: &RenderDevice,
595        pipeline_cache: &PipelineCache,
596        model: &BindingResource,
597        current_skin: &Buffer,
598        current_weights: &Buffer,
599        targets: MorphTargetsResource,
600        maybe_morph_descriptors: Option<&Buffer>,
601    ) -> BindGroup {
602        let mut entries: ArrayVec<BindGroupEntry, 5> = ArrayVec::new();
603
604        entries.extend([
605            entry::model(0, model.clone()),
606            entry::skinning(render_device, 1, current_skin),
607            entry::weights(render_device, 2, current_weights),
608            entry::targets(3, targets),
609        ]);
610
611        if let Some(morph_descriptors) = maybe_morph_descriptors {
612            entries.push(entry::morph_descriptors(8, morph_descriptors));
613        }
614
615        render_device.create_bind_group(
616            "morphed_skinned_mesh_bind_group",
617            &pipeline_cache.get_bind_group_layout(&self.morphed_skinned),
618            &entries,
619        )
620    }
621
622    /// Creates the bind group for meshes with skins and morph targets, in
623    /// addition to the infrastructure to compute motion vectors.
624    ///
625    /// See the documentation for [`MeshLayouts::skinned_motion`] and
626    /// [`MeshLayouts::morphed_motion`] above for more information about the
627    /// `current_skin`, `prev_skin`, `current_weights`, and `prev_weights`
628    /// buffers.
629    pub fn morphed_skinned_motion(
630        &self,
631        render_device: &RenderDevice,
632        pipeline_cache: &PipelineCache,
633        model: &BindingResource,
634        current_skin: &Buffer,
635        current_weights: &Buffer,
636        targets: MorphTargetsResource,
637        prev_skin: &Buffer,
638        prev_weights: &Buffer,
639        morph_descriptors: Option<&Buffer>,
640    ) -> BindGroup {
641        let mut entries: ArrayVec<BindGroupEntry, 7> = ArrayVec::new();
642
643        entries.extend([
644            entry::model(0, model.clone()),
645            entry::skinning(render_device, 1, current_skin),
646            entry::weights(render_device, 2, current_weights),
647            entry::targets(3, targets),
648            entry::skinning(render_device, 6, prev_skin),
649            entry::weights(render_device, 7, prev_weights),
650        ]);
651
652        if let Some(morph_descriptors) = morph_descriptors {
653            entries.push(entry::morph_descriptors(8, morph_descriptors));
654        }
655
656        render_device.create_bind_group(
657            "morphed_skinned_motion_mesh_bind_group",
658            &pipeline_cache.get_bind_group_layout(&self.morphed_skinned_motion),
659            &entries,
660        )
661    }
662}