Skip to main content

bevy_pbr/render/
morph.rs

1use core::{iter, mem};
2
3use bevy_camera::visibility::ViewVisibility;
4use bevy_derive::{Deref, DerefMut};
5use bevy_ecs::prelude::*;
6use bevy_mesh::morph::{MeshMorphWeights, MorphWeights, MAX_MORPH_WEIGHTS};
7use bevy_platform::collections::hash_map::Entry;
8use bevy_render::mesh::allocator::MeshAllocator;
9use bevy_render::mesh::RenderMesh;
10use bevy_render::render_asset::RenderAssets;
11use bevy_render::render_resource::ShaderType;
12use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
13use bevy_render::{
14    batching::NoAutomaticBatching,
15    render_resource::{BufferUsages, RawBufferVec},
16    renderer::{RenderDevice, RenderQueue},
17    Extract,
18};
19use bytemuck::{NoUninit, Pod, Zeroable};
20
21use crate::{skin, RenderMeshInstances};
22
23#[derive(Component)]
24pub struct MorphIndex {
25    pub index: u32,
26}
27
28/// The index of the [`GpuMorphDescriptor`] in the `morph_descriptors` buffer.
29#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Deref, DerefMut)]
30pub struct MorphDescriptorIndex(pub u32);
31
32/// Maps each mesh affected by morph targets to the applicable offset within the
33/// [`MorphUniforms`] buffer.
34///
35/// We store both the current frame's mapping and the previous frame's mapping
36/// for the purposes of motion vector calculation.
37#[derive(Resource)]
38pub enum MorphIndices {
39    /// The variant used when storage buffers aren't supported on the current
40    /// platform.
41    Uniform {
42        /// Maps each entity with a morphed mesh to the appropriate offset within
43        /// [`MorphUniforms::current_buffer`].
44        current: MainEntityHashMap<MorphIndex>,
45
46        /// Maps each entity with a morphed mesh to the appropriate offset within
47        /// [`MorphUniforms::prev_buffer`].
48        prev: MainEntityHashMap<MorphIndex>,
49    },
50
51    /// The variant used when storage buffers are supported on the current
52    /// platform.
53    Storage {
54        /// Maps each entity with a morphed mesh to the [`MorphWeightsInfo`].
55        morph_weights_info: MainEntityHashMap<MorphWeightsInfo>,
56        /// Maps each entity with a morphed mesh to the [`GpuMorphDescriptor`]
57        /// in the `morph_descriptors` buffer.
58        gpu_descriptor_indices: MainEntityHashMap<MorphDescriptorIndex>,
59        /// Indices in the `morph_descriptors` buffer available for use.
60        gpu_descriptor_free_list: Vec<MorphDescriptorIndex>,
61    },
62}
63
64/// Information that the CPU needs about each morh target for the purposes of
65/// weight calculation.
66#[derive(Clone, Copy)]
67pub struct MorphWeightsInfo {
68    /// The offset to the first weight for this mesh instance in the
69    /// `morph_weights` buffer.
70    current_weight_offset: u32,
71    /// The offset to the first weight for this mesh instance in the
72    /// `prev_morph_weights` buffer, if applicable
73    pub(crate) prev_weight_offset: Option<u32>,
74    /// The total number of morph targets that this mesh instance has.
75    weight_count: u32,
76}
77
78impl FromWorld for MorphIndices {
79    fn from_world(world: &mut World) -> MorphIndices {
80        let render_device = world.resource::<RenderDevice>();
81
82        if skin::skins_use_uniform_buffers(&render_device.limits()) {
83            MorphIndices::Uniform {
84                current: MainEntityHashMap::default(),
85                prev: MainEntityHashMap::default(),
86            }
87        } else {
88            MorphIndices::Storage {
89                morph_weights_info: MainEntityHashMap::default(),
90                gpu_descriptor_indices: MainEntityHashMap::default(),
91                gpu_descriptor_free_list: vec![],
92            }
93        }
94    }
95}
96
97/// The GPU buffers containing morph weights for all meshes with morph targets.
98///
99/// This is double-buffered: we store the weights of the previous frame in
100/// addition to those of the current frame. This is for motion vector
101/// calculation. Every frame, we swap buffers and reuse the morph target weight
102/// buffer from two frames ago for the current frame.
103#[derive(Resource)]
104pub struct MorphUniforms {
105    /// The morph weights for the current frame.
106    pub current_buffer: RawBufferVec<f32>,
107    /// The morph weights for the previous frame.
108    pub prev_buffer: RawBufferVec<f32>,
109    /// Information that the GPU needs about each morph target.
110    ///
111    /// This is only present if morph targets use storage buffers. If the
112    /// platform doesn't support storage buffers, we're using morph target
113    /// images instead, and the shader can determine the relevant info from the
114    /// texture dimensions.
115    pub descriptors_buffer: Option<RawBufferVec<GpuMorphDescriptor>>,
116}
117
118impl FromWorld for MorphUniforms {
119    fn from_world(world: &mut World) -> MorphUniforms {
120        let render_device = world.resource::<RenderDevice>();
121
122        let skins_use_uniform_buffers = skin::skins_use_uniform_buffers(&render_device.limits());
123
124        let buffer_usages = BufferUsages::COPY_DST
125            | (if skins_use_uniform_buffers {
126                BufferUsages::UNIFORM
127            } else {
128                BufferUsages::STORAGE
129            });
130
131        MorphUniforms {
132            current_buffer: RawBufferVec::new(buffer_usages),
133            prev_buffer: RawBufferVec::new(buffer_usages),
134            descriptors_buffer: if skins_use_uniform_buffers {
135                None
136            } else {
137                Some(RawBufferVec::new(
138                    BufferUsages::COPY_DST | BufferUsages::STORAGE,
139                ))
140            },
141        }
142    }
143}
144
145impl MorphUniforms {
146    /// Swaps the current buffer and previous buffer, and clears out the new
147    /// current buffer in preparation for a new frame.
148    fn prepare_for_new_frame(&mut self) {
149        mem::swap(&mut self.current_buffer, &mut self.prev_buffer);
150        self.current_buffer.clear();
151    }
152}
153
154impl MorphIndices {
155    /// Returns the index of the morph descriptor in the morph descriptor table
156    /// for the given entity.
157    ///
158    /// As morph descriptors are only present if the platform supports storage
159    /// buffers, this method returns `None` if the platform doesn't support
160    /// them.
161    pub fn morph_descriptor_index(&self, main_entity: MainEntity) -> Option<MorphDescriptorIndex> {
162        match *self {
163            MorphIndices::Uniform { .. } => None,
164            MorphIndices::Storage {
165                ref gpu_descriptor_indices,
166                ..
167            } => gpu_descriptor_indices.get(&main_entity).copied(),
168        }
169    }
170}
171
172/// Information that the GPU needs about a single mesh instance that uses morph
173/// targets.
174#[derive(Clone, Copy, Default, ShaderType, Pod, Zeroable)]
175#[repr(C)]
176pub struct GpuMorphDescriptor {
177    /// The index of the first morph target weight in the `morph_weights` array.
178    pub current_weights_offset: u32,
179    /// The index of the first morph target weight in the `prev_morph_weights`
180    /// array.
181    pub prev_weights_offset: u32,
182    /// The index of the first morph target for this mesh in the
183    /// `MorphAttributes` array.
184    pub targets_offset: u32,
185    /// The number of vertices in the mesh.
186    pub vertex_count: u32,
187    /// The number of morph targets this mesh has.
188    pub weight_count: u32,
189}
190
191/// A system that writes the buffers inside [`MorphUniforms`] to the GPU.
192pub fn write_morph_buffers(
193    render_device: Res<RenderDevice>,
194    render_queue: Res<RenderQueue>,
195    mut uniform: ResMut<MorphUniforms>,
196) {
197    if uniform.current_buffer.is_empty() {
198        return;
199    }
200    let len = uniform.current_buffer.len();
201    uniform.current_buffer.reserve(len, &render_device);
202    uniform
203        .current_buffer
204        .write_buffer(&render_device, &render_queue);
205
206    // We don't need to write `uniform.prev_buffer` because we already wrote it
207    // last frame, and the data should still be on the GPU.
208
209    if let Some(ref mut descriptors_buffer) = uniform.descriptors_buffer {
210        if descriptors_buffer.is_empty() {
211            descriptors_buffer.push(GpuMorphDescriptor::default());
212        }
213        descriptors_buffer.write_buffer(&render_device, &render_queue);
214    }
215}
216
217const fn can_align(step: usize, target: usize) -> bool {
218    step.is_multiple_of(target) || target.is_multiple_of(step)
219}
220
221const WGPU_MIN_ALIGN: usize = 256;
222
223/// Align a [`RawBufferVec`] to `N` bytes by padding the end with `T::default()` values.
224fn add_to_alignment<T: NoUninit + Default>(buffer: &mut RawBufferVec<T>) {
225    let n = WGPU_MIN_ALIGN;
226    let t_size = size_of::<T>();
227    if !can_align(n, t_size) {
228        // This panic is stripped at compile time, due to n, t_size and can_align being const
229        panic!(
230            "RawBufferVec should contain only types with a size multiple or divisible by {n}, \
231            {} has a size of {t_size}, which is neither multiple or divisible by {n}",
232            core::any::type_name::<T>()
233        );
234    }
235
236    let buffer_size = buffer.len();
237    let byte_size = t_size * buffer_size;
238    let bytes_over_n = byte_size % n;
239    if bytes_over_n == 0 {
240        return;
241    }
242    let bytes_to_add = n - bytes_over_n;
243    let ts_to_add = bytes_to_add / t_size;
244    buffer.extend(iter::repeat_with(T::default).take(ts_to_add));
245}
246
247// Notes on implementation: see comment on top of the extract_skins system in skin module.
248// This works similarly, but for `f32` instead of `Mat4`
249pub fn extract_morphs(
250    morph_indices: ResMut<MorphIndices>,
251    uniform: ResMut<MorphUniforms>,
252    query: Extract<Query<(Entity, &ViewVisibility, &MeshMorphWeights)>>,
253    weights_query: Extract<Query<&MorphWeights>>,
254    render_device: Res<RenderDevice>,
255) {
256    // Borrow check workaround.
257    let (morph_indices, uniform) = (morph_indices.into_inner(), uniform.into_inner());
258
259    let morphs_use_uniform_buffers = skin::skins_use_uniform_buffers(&render_device.limits());
260
261    // Swap buffers. We need to keep the previous frame's buffer around for the
262    // purposes of motion vector computation.
263    let maybe_old_morph_target_info = match *morph_indices {
264        MorphIndices::Uniform {
265            ref mut current,
266            ref mut prev,
267        } => {
268            mem::swap(current, prev);
269            current.clear();
270            None
271        }
272        MorphIndices::Storage {
273            morph_weights_info: ref mut morph_target_info,
274            ..
275        } => Some(mem::take(morph_target_info)),
276    };
277
278    uniform.prepare_for_new_frame();
279
280    // Loop over each entity with morph targets.
281    for (entity, view_visibility, mesh_weights) in &query {
282        if !view_visibility.get() {
283            continue;
284        }
285        let Ok(weights) = (match mesh_weights {
286            MeshMorphWeights::Reference(entity) => {
287                weights_query.get(*entity).map(MorphWeights::weights)
288            }
289            MeshMorphWeights::Value { weights } => Ok(weights.as_slice()),
290        }) else {
291            continue;
292        };
293
294        // Write the weights to the buffer. If we're using uniform buffers, then
295        // we have to pad out the buffer to its fixed length.
296        let start = uniform.current_buffer.len();
297        if morphs_use_uniform_buffers {
298            let legal_weights = weights
299                .iter()
300                .chain(iter::repeat(&0.0))
301                .take(MAX_MORPH_WEIGHTS)
302                .copied();
303            uniform.current_buffer.extend(legal_weights);
304            add_to_alignment::<f32>(&mut uniform.current_buffer);
305        } else {
306            uniform.current_buffer.extend(weights.iter().copied());
307        }
308
309        // Find the index of the weights for the previous frame in the buffer.
310        let maybe_prev_weights_offset =
311            maybe_old_morph_target_info
312                .as_ref()
313                .and_then(|old_morph_target_info| {
314                    old_morph_target_info
315                        .get(&MainEntity::from(entity))
316                        .map(|morph_target_info| morph_target_info.current_weight_offset)
317                });
318
319        // Store the location of the weights for future use.
320        match *morph_indices {
321            MorphIndices::Uniform {
322                ref mut current, ..
323            } => {
324                let index = (start * size_of::<f32>()) as u32;
325                current.insert(entity.into(), MorphIndex { index });
326            }
327            MorphIndices::Storage {
328                morph_weights_info: ref mut morph_target_info,
329                ..
330            } => {
331                morph_target_info.insert(
332                    entity.into(),
333                    MorphWeightsInfo {
334                        current_weight_offset: start as u32,
335                        prev_weight_offset: maybe_prev_weights_offset,
336                        weight_count: weights.len() as u32,
337                    },
338                );
339            }
340        }
341    }
342}
343
344/// A system that writes [`GpuMorphDescriptor`] values to the [`MorphUniforms`]
345/// for each mesh instance with morph targets.
346///
347/// As morph descriptors are only used when the platform supports storage
348/// buffers, if the platform doesn't support storage buffers, this system does
349/// nothing.
350pub fn prepare_morph_descriptors(
351    mut morph_indices: ResMut<MorphIndices>,
352    mut morph_uniforms: ResMut<MorphUniforms>,
353    render_mesh_instances: Res<RenderMeshInstances>,
354    meshes: Res<RenderAssets<RenderMesh>>,
355    mesh_allocator: Res<MeshAllocator>,
356) {
357    // Don't do anything unless the platform supports storage buffers.
358    let (
359        &mut MorphIndices::Storage {
360            morph_weights_info: ref morph_target_info,
361            ref mut gpu_descriptor_indices,
362            ref mut gpu_descriptor_free_list,
363        },
364        &mut Some(ref mut descriptors_buffer),
365    ) = (&mut *morph_indices, &mut morph_uniforms.descriptors_buffer)
366    else {
367        return;
368    };
369
370    for (&morph_target_main_entity, morph_target_info) in morph_target_info {
371        let Some(mesh_id) = render_mesh_instances.mesh_asset_id(morph_target_main_entity) else {
372            continue;
373        };
374        let Some(mesh) = meshes.get(mesh_id) else {
375            continue;
376        };
377        let Some(morph_targets_slice) = mesh_allocator.mesh_morph_target_slice(&mesh_id) else {
378            continue;
379        };
380
381        // Create our morph descriptor.
382        let morph_descriptor = GpuMorphDescriptor {
383            current_weights_offset: morph_target_info.current_weight_offset,
384            prev_weights_offset: morph_target_info.prev_weight_offset.unwrap_or(!0),
385            targets_offset: morph_targets_slice.range.start,
386            vertex_count: mesh.vertex_count,
387            weight_count: morph_target_info.weight_count,
388        };
389
390        // Place it in the descriptors buffer. Note that if the morph target
391        // descriptor for an entity was in the buffer last frame, then it must
392        // be at the same index this frame. That's because the
393        // `MeshInputUniform` stores the index of the morph target descriptor,
394        // and `MeshInputUniform`s aren't updated unless the mesh instance
395        // changes.
396        let descriptor_index;
397        match gpu_descriptor_indices.entry(morph_target_main_entity) {
398            Entry::Occupied(occupied_entry) => {
399                descriptor_index = *occupied_entry.get();
400                descriptors_buffer.set(descriptor_index.0, morph_descriptor);
401            }
402            Entry::Vacant(vacant_entry) => {
403                match gpu_descriptor_free_list.pop() {
404                    Some(free_descriptor_index) => {
405                        descriptor_index = free_descriptor_index;
406                        descriptors_buffer.set(descriptor_index.0, morph_descriptor);
407                    }
408                    None => {
409                        descriptor_index =
410                            MorphDescriptorIndex(descriptors_buffer.push(morph_descriptor) as u32);
411                    }
412                }
413                vacant_entry.insert(descriptor_index);
414            }
415        };
416
417        // Note where we wrote it.
418        gpu_descriptor_indices.insert(morph_target_main_entity, descriptor_index);
419    }
420
421    // Expire descriptor indices corresponding to entities no longer present.
422    gpu_descriptor_indices.retain(|morph_target_main_entity, descriptor_index| {
423        let live = morph_target_info.contains_key(morph_target_main_entity);
424        if !live {
425            gpu_descriptor_free_list.push(*descriptor_index);
426        }
427        live
428    });
429}
430
431// NOTE: Because morph targets require per-morph target texture bindings, they cannot
432// currently be batched on platforms without storage buffers.
433pub fn no_automatic_morph_batching(
434    mut commands: Commands,
435    query: Query<Entity, (With<MeshMorphWeights>, Without<NoAutomaticBatching>)>,
436    render_device: Res<RenderDevice>,
437) {
438    // We *can* batch mesh instances with morph targets if the platform supports
439    // storage buffers.
440    if !skin::skins_use_uniform_buffers(&render_device.limits()) {
441        return;
442    }
443
444    for entity in &query {
445        commands.entity(entity).try_insert(NoAutomaticBatching);
446    }
447}