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