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