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}