bevy_render/mesh/
morph.rs

1use crate::{
2    mesh::Mesh,
3    render_asset::RenderAssetUsages,
4    render_resource::{Extent3d, TextureDimension, TextureFormat},
5    texture::Image,
6};
7use bevy_app::{Plugin, PostUpdate};
8use bevy_asset::Handle;
9use bevy_ecs::prelude::*;
10use bevy_hierarchy::Children;
11use bevy_math::Vec3;
12use bevy_reflect::prelude::*;
13use bytemuck::{Pod, Zeroable};
14use std::{iter, mem};
15use thiserror::Error;
16
17const MAX_TEXTURE_WIDTH: u32 = 2048;
18// NOTE: "component" refers to the element count of math objects,
19// Vec3 has 3 components, Mat2 has 4 components.
20const MAX_COMPONENTS: u32 = MAX_TEXTURE_WIDTH * MAX_TEXTURE_WIDTH;
21
22/// Max target count available for [morph targets](MorphWeights).
23pub const MAX_MORPH_WEIGHTS: usize = 64;
24
25/// [Inherit weights](inherit_weights) from glTF mesh parent entity to direct
26/// bevy mesh child entities (ie: glTF primitive).
27pub struct MorphPlugin;
28impl Plugin for MorphPlugin {
29    fn build(&self, app: &mut bevy_app::App) {
30        app.register_type::<MorphWeights>()
31            .register_type::<MeshMorphWeights>()
32            .add_systems(PostUpdate, inherit_weights);
33    }
34}
35
36#[derive(Error, Clone, Debug)]
37pub enum MorphBuildError {
38    #[error(
39        "Too many vertexĂ—components in morph target, max is {MAX_COMPONENTS}, \
40        got {vertex_count}Ă—{component_count} = {}",
41        *vertex_count * *component_count as usize
42    )]
43    TooManyAttributes {
44        vertex_count: usize,
45        component_count: u32,
46    },
47    #[error(
48        "Bevy only supports up to {} morph targets (individual poses), tried to \
49        create a model with {target_count} morph targets",
50        MAX_MORPH_WEIGHTS
51    )]
52    TooManyTargets { target_count: usize },
53}
54
55/// An image formatted for use with [`MorphWeights`] for rendering the morph target.
56#[derive(Debug)]
57pub struct MorphTargetImage(pub Image);
58
59impl MorphTargetImage {
60    /// Generate textures for each morph target.
61    ///
62    /// This accepts an "iterator of [`MorphAttributes`] iterators". Each item iterated in the top level
63    /// iterator corresponds "the attributes of a specific morph target".
64    ///
65    /// Each pixel of the texture is a component of morph target animated
66    /// attributes. So a set of 9 pixels is this morph's displacement for
67    /// position, normal and tangents of a single vertex (each taking 3 pixels).
68    pub fn new(
69        targets: impl ExactSizeIterator<Item = impl Iterator<Item = MorphAttributes>>,
70        vertex_count: usize,
71        asset_usage: RenderAssetUsages,
72    ) -> Result<Self, MorphBuildError> {
73        let max = MAX_TEXTURE_WIDTH;
74        let target_count = targets.len();
75        if target_count > MAX_MORPH_WEIGHTS {
76            return Err(MorphBuildError::TooManyTargets { target_count });
77        }
78        let component_count = (vertex_count * MorphAttributes::COMPONENT_COUNT) as u32;
79        let Some((Rect(width, height), padding)) = lowest_2d(component_count, max) else {
80            return Err(MorphBuildError::TooManyAttributes {
81                vertex_count,
82                component_count,
83            });
84        };
85        let data = targets
86            .flat_map(|mut attributes| {
87                let layer_byte_count = (padding + component_count) as usize * mem::size_of::<f32>();
88                let mut buffer = Vec::with_capacity(layer_byte_count);
89                for _ in 0..vertex_count {
90                    let Some(to_add) = attributes.next() else {
91                        break;
92                    };
93                    buffer.extend_from_slice(bytemuck::bytes_of(&to_add));
94                }
95                // Pad each layer so that they fit width * height
96                buffer.extend(iter::repeat(0).take(padding as usize * mem::size_of::<f32>()));
97                debug_assert_eq!(buffer.len(), layer_byte_count);
98                buffer
99            })
100            .collect();
101        let extents = Extent3d {
102            width,
103            height,
104            depth_or_array_layers: target_count as u32,
105        };
106        let image = Image::new(
107            extents,
108            TextureDimension::D3,
109            data,
110            TextureFormat::R32Float,
111            asset_usage,
112        );
113        Ok(MorphTargetImage(image))
114    }
115}
116
117/// Controls the [morph targets] for all child [`Handle<Mesh>`] entities. In most cases, [`MorphWeights`] should be considered
118/// the "source of truth" when writing morph targets for meshes. However you can choose to write child [`MeshMorphWeights`]
119/// if your situation requires more granularity. Just note that if you set [`MorphWeights`], it will overwrite child
120/// [`MeshMorphWeights`] values.
121///
122/// This exists because Bevy's [`Mesh`] corresponds to a _single_ surface / material, whereas morph targets
123/// as defined in the GLTF spec exist on "multi-primitive meshes" (where each primitive is its own surface with its own material).
124/// Therefore in Bevy [`MorphWeights`] an a parent entity are the "canonical weights" from a GLTF perspective, which then
125/// synchronized to child [`Handle<Mesh>`] / [`MeshMorphWeights`] (which correspond to "primitives" / "surfaces" from a GLTF perspective).
126///
127/// Add this to the parent of one or more [`Entities`](`Entity`) with a [`Handle<Mesh>`] with a [`MeshMorphWeights`].
128///
129/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
130#[derive(Reflect, Default, Debug, Clone, Component)]
131#[reflect(Debug, Component, Default)]
132pub struct MorphWeights {
133    weights: Vec<f32>,
134    /// The first mesh primitive assigned to these weights
135    first_mesh: Option<Handle<Mesh>>,
136}
137impl MorphWeights {
138    pub fn new(
139        weights: Vec<f32>,
140        first_mesh: Option<Handle<Mesh>>,
141    ) -> Result<Self, MorphBuildError> {
142        if weights.len() > MAX_MORPH_WEIGHTS {
143            let target_count = weights.len();
144            return Err(MorphBuildError::TooManyTargets { target_count });
145        }
146        Ok(MorphWeights {
147            weights,
148            first_mesh,
149        })
150    }
151    /// The first child [`Handle<Mesh>`] primitive controlled by these weights.
152    /// This can be used to look up metadata information such as [`Mesh::morph_target_names`].
153    pub fn first_mesh(&self) -> Option<&Handle<Mesh>> {
154        self.first_mesh.as_ref()
155    }
156    pub fn weights(&self) -> &[f32] {
157        &self.weights
158    }
159    pub fn weights_mut(&mut self) -> &mut [f32] {
160        &mut self.weights
161    }
162}
163
164/// Control a specific [`Mesh`] instance's [morph targets]. These control the weights of
165/// specific "mesh primitives" in scene formats like GLTF. They can be set manually, but
166/// in most cases they should "automatically" synced by setting the [`MorphWeights`] component
167/// on a parent entity.
168///
169/// See [`MorphWeights`] for more details on Bevy's morph target implementation.
170///
171/// Add this to an [`Entity`] with a [`Handle<Mesh>`] with a [`MorphAttributes`] set
172/// to control individual weights of each morph target.
173///
174/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
175#[derive(Reflect, Default, Debug, Clone, Component)]
176#[reflect(Debug, Component, Default)]
177pub struct MeshMorphWeights {
178    weights: Vec<f32>,
179}
180impl MeshMorphWeights {
181    pub fn new(weights: Vec<f32>) -> Result<Self, MorphBuildError> {
182        if weights.len() > MAX_MORPH_WEIGHTS {
183            let target_count = weights.len();
184            return Err(MorphBuildError::TooManyTargets { target_count });
185        }
186        Ok(MeshMorphWeights { weights })
187    }
188    pub fn weights(&self) -> &[f32] {
189        &self.weights
190    }
191    pub fn weights_mut(&mut self) -> &mut [f32] {
192        &mut self.weights
193    }
194}
195
196/// Bevy meshes are gltf primitives, [`MorphWeights`] on the bevy node entity
197/// should be inherited by children meshes.
198///
199/// Only direct children are updated, to fulfill the expectations of glTF spec.
200pub fn inherit_weights(
201    morph_nodes: Query<(&Children, &MorphWeights), (Without<Handle<Mesh>>, Changed<MorphWeights>)>,
202    mut morph_primitives: Query<&mut MeshMorphWeights, With<Handle<Mesh>>>,
203) {
204    for (children, parent_weights) in &morph_nodes {
205        let mut iter = morph_primitives.iter_many_mut(children);
206        while let Some(mut child_weight) = iter.fetch_next() {
207            child_weight.weights.clear();
208            child_weight.weights.extend(&parent_weights.weights);
209        }
210    }
211}
212
213/// Attributes **differences** used for morph targets.
214///
215/// See [`MorphTargetImage`] for more information.
216#[derive(Copy, Clone, PartialEq, Pod, Zeroable, Default)]
217#[repr(C)]
218pub struct MorphAttributes {
219    /// The vertex position difference between base mesh and this target.
220    pub position: Vec3,
221    /// The vertex normal difference between base mesh and this target.
222    pub normal: Vec3,
223    /// The vertex tangent difference between base mesh and this target.
224    ///
225    /// Note that tangents are a `Vec4`, but only the `xyz` components are
226    /// animated, as the `w` component is the sign and cannot be animated.
227    pub tangent: Vec3,
228}
229impl From<[Vec3; 3]> for MorphAttributes {
230    fn from([position, normal, tangent]: [Vec3; 3]) -> Self {
231        MorphAttributes {
232            position,
233            normal,
234            tangent,
235        }
236    }
237}
238impl MorphAttributes {
239    /// How many components `MorphAttributes` has.
240    ///
241    /// Each `Vec3` has 3 components, we have 3 `Vec3`, for a total of 9.
242    pub const COMPONENT_COUNT: usize = 9;
243
244    pub fn new(position: Vec3, normal: Vec3, tangent: Vec3) -> Self {
245        MorphAttributes {
246            position,
247            normal,
248            tangent,
249        }
250    }
251}
252
253/// Integer division rounded up.
254const fn div_ceil(lhf: u32, rhs: u32) -> u32 {
255    (lhf + rhs - 1) / rhs
256}
257struct Rect(u32, u32);
258
259/// Find the smallest rectangle of maximum edge size `max_edge` that contains
260/// at least `min_includes` cells. `u32` is how many extra cells the rectangle
261/// has.
262///
263/// The following rectangle contains 27 cells, and its longest edge is 9:
264/// ```text
265/// ----------------------------
266/// |1 |2 |3 |4 |5 |6 |7 |8 |9 |
267/// ----------------------------
268/// |2 |  |  |  |  |  |  |  |  |
269/// ----------------------------
270/// |3 |  |  |  |  |  |  |  |  |
271/// ----------------------------
272/// ```
273///
274/// Returns `None` if `max_edge` is too small to build a rectangle
275/// containing `min_includes` cells.
276fn lowest_2d(min_includes: u32, max_edge: u32) -> Option<(Rect, u32)> {
277    (1..=max_edge)
278        .filter_map(|a| {
279            let b = div_ceil(min_includes, a);
280            let diff = (a * b).checked_sub(min_includes)?;
281            Some((Rect(a, b), diff))
282        })
283        .filter_map(|(rect, diff)| (rect.1 <= max_edge).then_some((rect, diff)))
284        .min_by_key(|(_, diff)| *diff)
285}