Skip to main content

bevy_mesh/
morph.rs

1use super::Mesh;
2use bevy_asset::Handle;
3use bevy_ecs::prelude::*;
4use bevy_math::Vec3;
5use bevy_reflect::prelude::*;
6use bytemuck::{Pod, Zeroable};
7use encase::ShaderType;
8use thiserror::Error;
9
10/// The maximum size of the morph target texture, if morph target textures are
11/// in use on the current platform.
12pub const MAX_TEXTURE_WIDTH: u32 = 2048;
13
14/// Max target count available for [morph targets](MorphWeights).
15pub const MAX_MORPH_WEIGHTS: usize = 256;
16
17/// The maximum number of morph target components, if morph target textures are
18/// in use on the current platform.
19///
20/// NOTE: "component" refers to the element count of math objects,
21/// Vec3 has 3 components, Mat2 has 4 components.
22const MAX_COMPONENTS: u32 = MAX_TEXTURE_WIDTH * MAX_TEXTURE_WIDTH;
23
24#[derive(Error, Clone, Debug)]
25pub enum MorphBuildError {
26    #[error(
27        "Too many vertex components in morph target, max is {MAX_COMPONENTS}, \
28        got {vertex_count}×{component_count} = {}",
29        *vertex_count * *component_count as usize
30    )]
31    TooManyAttributes {
32        vertex_count: usize,
33        component_count: u32,
34    },
35    #[error(
36        "Bevy only supports up to {} morph targets (individual poses), tried to \
37        create a model with {target_count} morph targets",
38        MAX_MORPH_WEIGHTS
39    )]
40    TooManyTargets { target_count: usize },
41}
42
43/// Controls the [morph targets] for all child [`Mesh3d`](crate::Mesh3d)
44/// entities. In most cases, [`MorphWeights`] should be considered the "source
45/// of truth" when writing [morph targets] for meshes. However you can choose to
46/// write child [`MeshMorphWeights`] if your situation requires more
47/// granularity. Just note that if you set [`MorphWeights`], it will overwrite
48/// child [`MeshMorphWeights`] values.
49///
50/// `MorphWeights` works together with the [`MeshMorphWeights`] component. When
51/// a `MeshMorphWeights` is set to `MeshMorphWeights::Reference`, it references
52/// another entity that is expected to contain a `MorphWeights` component. This
53/// allows multiple meshes to share a single `MorphWeights` component.
54///
55/// ```
56/// # use bevy_asset::prelude::*;
57/// # use bevy_ecs::prelude::*;
58/// # use bevy_mesh::Mesh;
59/// # use bevy_mesh::morph::*;
60/// # #[derive(Component)]
61/// # struct Mesh3d(Handle<Mesh>);
62/// fn setup(mut commands: Commands, mesh_handle: Handle<Mesh>) {
63///     // Create the `MorphWeights` component.
64///     let weights_component = MorphWeights::new(vec![0.0, 0.5, 1.0], None).unwrap();
65///
66///     // Spawn an entity that contains the `MorphWeights` component.
67///     let weights_entity = commands.spawn(weights_component).id();
68///
69///     // Spawn another entity with a mesh and a `MeshMorphWeights` component
70///     // that references `weights_entity`.
71///     let mesh_entity = commands.spawn((
72///         Mesh3d(mesh_handle.clone()),
73///         MeshMorphWeights::Reference(weights_entity),
74///     ));
75/// }
76/// ```
77///
78/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
79#[derive(Reflect, Default, Debug, Clone, Component)]
80#[reflect(Debug, Component, Default, Clone)]
81pub struct MorphWeights {
82    weights: Vec<f32>,
83    /// The first mesh primitive assigned to these weights
84    first_mesh: Option<Handle<Mesh>>,
85}
86
87impl MorphWeights {
88    pub fn new(
89        weights: Vec<f32>,
90        first_mesh: Option<Handle<Mesh>>,
91    ) -> Result<Self, MorphBuildError> {
92        if weights.len() > MAX_MORPH_WEIGHTS {
93            let target_count = weights.len();
94            return Err(MorphBuildError::TooManyTargets { target_count });
95        }
96        Ok(MorphWeights {
97            weights,
98            first_mesh,
99        })
100    }
101    /// The first child [`Mesh3d`](crate::Mesh3d) primitive controlled by these weights.
102    /// This can be used to look up metadata information such as [`Mesh::morph_target_names`].
103    pub fn first_mesh(&self) -> Option<&Handle<Mesh>> {
104        self.first_mesh.as_ref()
105    }
106    pub fn weights(&self) -> &[f32] {
107        &self.weights
108    }
109    pub fn weights_mut(&mut self) -> &mut [f32] {
110        &mut self.weights
111    }
112}
113
114/// A component that controls the [morph targets] of a mesh. Must be assigned
115/// to an entity with a [`Mesh3d`](crate::Mesh3d) component.
116///
117/// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation
118#[derive(Reflect, Debug, Clone, Component)]
119#[reflect(Debug, Component, Clone)]
120pub enum MeshMorphWeights {
121    Value {
122        weights: Vec<f32>,
123    },
124    /// A reference to an entity containing a [`MorphWeights`] component. This
125    /// allows a single `MorphWeights` component to control the morph targets
126    /// of multiple meshes.
127    ///
128    /// See [`MorphWeights`] for an example.
129    Reference(#[entities] Entity),
130}
131
132/// Attributes **differences** used for morph targets.
133#[derive(Copy, Clone, PartialEq, Debug, Reflect, ShaderType, Pod, Zeroable, Default)]
134#[reflect(Clone, Default)]
135#[repr(C)]
136pub struct MorphAttributes {
137    /// The vertex position difference between base mesh and this target.
138    pub position: Vec3,
139    /// Padding to ensure that vectors start on 16-byte boundaries.
140    pub pad_a: f32,
141    /// The vertex normal difference between base mesh and this target.
142    pub normal: Vec3,
143    /// Padding to ensure that vectors start on 16-byte boundaries.
144    pub pad_b: f32,
145    /// The vertex tangent difference between base mesh and this target.
146    ///
147    /// Note that tangents are a `Vec4`, but only the `xyz` components are
148    /// animated, as the `w` component is the sign and cannot be animated.
149    pub tangent: Vec3,
150    /// Padding to ensure that vectors start on 16-byte boundaries.
151    pub pad_c: f32,
152}
153
154impl From<[Vec3; 3]> for MorphAttributes {
155    fn from([position, normal, tangent]: [Vec3; 3]) -> Self {
156        MorphAttributes {
157            position,
158            normal,
159            tangent,
160            pad_a: 0.0,
161            pad_b: 0.0,
162            pad_c: 0.0,
163        }
164    }
165}
166
167impl MorphAttributes {
168    /// How many components `MorphAttributes` has.
169    ///
170    /// Each `Vec3` has 3 components, we have 3 `Vec3`, for a total of 9.
171    pub const COMPONENT_COUNT: usize = 9;
172
173    pub fn new(position: Vec3, normal: Vec3, tangent: Vec3) -> Self {
174        MorphAttributes {
175            position,
176            normal,
177            tangent,
178            pad_a: 0.0,
179            pad_b: 0.0,
180            pad_c: 0.0,
181        }
182    }
183}