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