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;
18const MAX_COMPONENTS: u32 = MAX_TEXTURE_WIDTH * MAX_TEXTURE_WIDTH;
21
22pub const MAX_MORPH_WEIGHTS: usize = 64;
24
25pub 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#[derive(Debug)]
57pub struct MorphTargetImage(pub Image);
58
59impl MorphTargetImage {
60 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 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#[derive(Reflect, Default, Debug, Clone, Component)]
131#[reflect(Debug, Component, Default)]
132pub struct MorphWeights {
133 weights: Vec<f32>,
134 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 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#[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
196pub 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#[derive(Copy, Clone, PartialEq, Pod, Zeroable, Default)]
217#[repr(C)]
218pub struct MorphAttributes {
219 pub position: Vec3,
221 pub normal: Vec3,
223 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 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
253const fn div_ceil(lhf: u32, rhs: u32) -> u32 {
255 (lhf + rhs - 1) / rhs
256}
257struct Rect(u32, u32);
258
259fn 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}