remove registry stubs and get compilation working again

This commit is contained in:
Lee-Orr
2024-02-12 11:45:43 -05:00
parent 9de7202764
commit 952908630e
3 changed files with 100 additions and 76 deletions
+1
View File
@@ -10,6 +10,7 @@ edition = "2021"
bevy = { version = "0.12", default-features = false, features = ["bevy_pbr", "bevy_render", "bevy_asset", "animation", "bevy_animation"]} bevy = { version = "0.12", default-features = false, features = ["bevy_pbr", "bevy_render", "bevy_asset", "animation", "bevy_animation"]}
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
csv = "1.3" csv = "1.3"
serde_json = "1"
[dev-dependencies] [dev-dependencies]
bevy = { version = "0.12", default-features = true } bevy = { version = "0.12", default-features = true }
+3 -6
View File
@@ -4,7 +4,7 @@ use bevy::{
pbr::{CascadeShadowConfigBuilder, DirectionalLightShadowMap}, pbr::{CascadeShadowConfigBuilder, DirectionalLightShadowMap},
prelude::*, prelude::*,
}; };
use bevy_facial_mocap::{CSVAnimationLoader, CSVAnimationLoaderSettings}; use bevy_facial_mocap::CSVAnimationLoader;
use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_inspector_egui::quick::WorldInspectorPlugin;
fn main() { fn main() {
@@ -57,11 +57,8 @@ fn setup_animation(
mut players: Query<Entity, (With<MorphWeights>, Without<AnimationRunning>)>, mut players: Query<Entity, (With<MorphWeights>, Without<AnimationRunning>)>,
) { ) {
for entity in &mut players { for entity in &mut players {
let handle = asset_server.load_with_settings( let handle = asset_server.load(
"20240205_shapekey_BevyImplementationFaceCap_5/fake_test.morph_anim.csv", "20240205_shapekey_BevyImplementationFaceCap_5/fake_test.morph_anim.csv"
|s: &mut CSVAnimationLoaderSettings| {
s.0.parts = vec![Name::new("pascal_Head")];
},
); );
let mut player = AnimationPlayer::default(); let mut player = AnimationPlayer::default();
player.play(handle.clone()).repeat(); player.play(handle.clone()).repeat();
+96 -70
View File
@@ -2,10 +2,14 @@ use std::{num::ParseFloatError, str::FromStr};
use bevy::{ use bevy::{
animation::{AnimationClip, EntityPath, Keyframes, VariableCurve}, animation::{AnimationClip, EntityPath, Keyframes, VariableCurve},
asset::{Asset, AssetLoader, AsyncReadExt}, app::{Plugin, PostUpdate},
asset::{Asset, AssetApp, AssetLoader, Assets, AsyncReadExt, Handle},
core::Name, core::Name,
ecs::{change_detection::DetectChanges, system::{Res, ResMut, Resource}},
log::info, log::info,
reflect::Reflect, reflect::Reflect,
render::mesh::Mesh,
utils::{hashbrown::HashMap, HashSet},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -204,35 +208,54 @@ impl CSVAnimation {
} }
} }
impl From<CSVAnimation> for VariableCurve { impl CSVAnimation {
fn from(value: CSVAnimation) -> Self { fn generate_clip(self, name: &str, mesh: &Mesh) -> AnimationClip {
let mut keyframe_timestamps = Vec::with_capacity(value.frames.len()); let path = EntityPath {
let mut keyframes = Vec::with_capacity(value.frames.len() * value.morph_names.len()); parts: vec![Name::new(name.to_owned())],
};
let mut clip = AnimationClip::default();
clip.add_curve_to_path(path, self.generate_animation_curve(mesh));
let seconds_per_frame = 1.0 / (value.fps as f32); clip
for (frame, data) in value.frames.iter().enumerate() { }
fn generate_animation_curve(self, mesh: &Mesh) -> VariableCurve {
let mesh_morph_names = mesh.morph_target_names().unwrap_or_default();
let csv_morph_order: HashMap<&str, usize> = self
.morph_names
.iter()
.enumerate()
.map(|(i, val)| (val.as_str(), i))
.collect();
let num_mesh_morphs: usize = mesh_morph_names.len();
let mesh_to_csv_morph_order: Vec<Option<usize>> = mesh_morph_names
.iter()
.map(|v| csv_morph_order.get(v.as_str()).copied())
.collect();
let mut keyframe_timestamps = Vec::with_capacity(self.frames.len());
let mut keyframes = Vec::with_capacity(self.frames.len() * num_mesh_morphs);
let seconds_per_frame = 1.0 / (self.fps as f32);
for (frame, data) in self.frames.iter().enumerate() {
let time = (frame as f32) * seconds_per_frame; let time = (frame as f32) * seconds_per_frame;
let mut morphs = data.morphs.clone();
keyframe_timestamps.push(time); keyframe_timestamps.push(time);
keyframes.append(&mut morphs); for i in 0..num_mesh_morphs {
let result = mesh_to_csv_morph_order
.get(i)
.and_then(|i| i.map(|i| data.morphs.get(i).copied().unwrap_or(0.0)))
.unwrap_or(0.0);
keyframes.push(result);
}
} }
Self { VariableCurve {
keyframe_timestamps, keyframe_timestamps,
keyframes: Keyframes::Weights(keyframes), keyframes: Keyframes::Weights(keyframes),
} }
} }
} }
impl CSVAnimation {
fn generate_clip(self, path: &EntityPath) -> AnimationClip {
let mut clip = AnimationClip::default();
clip.add_curve_to_path(path.clone(), self.into());
clip
}
}
#[derive(Default)] #[derive(Default)]
pub struct CSVAnimationLoader; pub struct CSVAnimationLoader;
@@ -251,47 +274,17 @@ impl std::fmt::Display for CSVAnimationLoaderError {
impl std::error::Error for CSVAnimationLoaderError {} impl std::error::Error for CSVAnimationLoaderError {}
#[derive(Default)]
pub struct CSVAnimationLoaderSettings(pub EntityPath);
impl Serialize for CSVAnimationLoaderSettings {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let names = self
.0
.parts
.iter()
.map(|name| name.to_string())
.collect::<Vec<String>>();
names.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for CSVAnimationLoaderSettings {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let names = Vec::<String>::deserialize(deserializer)?;
Ok(CSVAnimationLoaderSettings(EntityPath {
parts: names.into_iter().map(Name::new).collect(),
}))
}
}
impl AssetLoader for CSVAnimationLoader { impl AssetLoader for CSVAnimationLoader {
type Asset = AnimationClip; type Asset = CSVAnimation;
type Settings = CSVAnimationLoaderSettings; type Settings = ();
type Error = CSVAnimationLoaderError; type Error = CSVAnimationLoaderError;
fn load<'a>( fn load<'a>(
&'a self, &'a self,
reader: &'a mut bevy::asset::io::Reader, reader: &'a mut bevy::asset::io::Reader,
settings: &'a Self::Settings, _settings: &'a Self::Settings,
_load_context: &'a mut bevy::asset::LoadContext, _load_context: &'a mut bevy::asset::LoadContext,
) -> bevy::utils::BoxedFuture<'a, Result<Self::Asset, Self::Error>> { ) -> bevy::utils::BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
Box::pin(async move { Box::pin(async move {
@@ -309,11 +302,7 @@ impl AssetLoader for CSVAnimationLoader {
csv_animation.frames.len() csv_animation.frames.len()
); );
let animation = csv_animation.generate_clip(&settings.0); Ok(csv_animation)
info!("Clip has duration of {}", animation.duration());
Ok(animation)
}) })
} }
@@ -322,10 +311,24 @@ impl AssetLoader for CSVAnimationLoader {
} }
} }
pub struct CSVAnimationPlugin;
impl Plugin for CSVAnimationPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.init_asset::<CSVAnimation>()
.init_asset_loader::<CSVAnimationLoader>();
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use bevy::animation::{AnimationClip, EntityPath, Keyframes}; use bevy::{
animation::{AnimationClip, EntityPath, Keyframes},
core::Name,
math::Vec3,
render::mesh::{Indices, Mesh},
};
use crate::{CSVAnimation, CSVParseError, Timestamp, TimestampParseError}; use crate::{CSVAnimation, CSVParseError, Timestamp, TimestampParseError};
#[test] #[test]
@@ -458,22 +461,42 @@ mod tests {
#[test] #[test]
fn can_convert_an_animation_into_an_animation_clip() { fn can_convert_an_animation_into_an_animation_clip() {
let animation = CSVAnimation::parse( let animation = CSVAnimation::parse(
"timecode, blendshapecount, shape_1, shape_2 "timecode, blendshapecount, shape_1, shape_2, shape_missing
00:00:00:00.00, 0, 1.0, 0 00:00:00:00.00, 0, 1.0, 0, 0.5
00:00:00:01.00, 0, 0, -0.4 00:00:00:01.00, 0, 0, -0.4, 0.2
00:00:00:02.00, 0, 0, 0 00:00:00:02.00, 0, 0, 0, 0.4
00:00:01:00.00, 0, 0, 0 00:00:01:00.00, 0, 0, 0, 1
00:00:01:01.00, 0, 0, 0", 00:00:01:01.00, 0, 0, 0, -2",
) )
.unwrap(); .unwrap();
let clip: AnimationClip = animation.generate_clip(&EntityPath::default()); let mut mesh = Mesh::new(bevy::render::render_resource::PrimitiveTopology::TriangleList);
mesh.set_indices(Some(Indices::U16(vec![0, 1, 2])));
mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![Vec3::ZERO, Vec3::ONE, Vec3::NEG_ONE],
);
// Setting these in reverse order with an extra shape key and a missing one to validate resiliency
mesh.set_morph_target_names(vec![
"shape_2".to_string(),
"shape_1".to_string(),
"shape_extra".to_string(),
]);
let clip: AnimationClip = animation.generate_clip("my_node", &mesh);
assert!(clip.duration() - 1.33333 < 0.1); assert!(clip.duration() - 1.33333 < 0.1);
let curves = clip let curves = clip
.get_curves_by_path(&EntityPath::default()) .get_curves_by_path(&EntityPath {
parts: vec![Name::new("my_node")],
})
.unwrap() .unwrap()
.first() .first()
.unwrap(); .unwrap();
assert_eq!(curves.keyframe_timestamps.len(), 5); assert_eq!(curves.keyframe_timestamps.len(), 5);
assert!((curves.keyframe_timestamps[0] - 0.0).abs() < 0.001); assert!((curves.keyframe_timestamps[0] - 0.0).abs() < 0.001);
assert!((curves.keyframe_timestamps[1] - 0.33333).abs() < 0.001); assert!((curves.keyframe_timestamps[1] - 0.33333).abs() < 0.001);
assert!((curves.keyframe_timestamps[2] - 0.66666).abs() < 0.01); assert!((curves.keyframe_timestamps[2] - 0.66666).abs() < 0.01);
@@ -484,10 +507,13 @@ mod tests {
panic!("Keyframes aren't weights") panic!("Keyframes aren't weights")
}; };
assert_eq!(keyframes.len(), 10); assert_eq!(keyframes.len(), 15);
assert!((keyframes[0] - 1.0).abs() < 0.0001);
assert!((keyframes[1] - 0.0).abs() < 0.0001); assert!((keyframes[1] - 1.0).abs() < 0.0001); // "shape_1" is the second morph in the mesh
assert!((keyframes[2] - 0.0).abs() < 0.0001); assert!((keyframes[0] - 0.0).abs() < 0.0001); // "shape_2" is the first morph in the mesh
assert!((keyframes[2] - 0.0).abs() < 0.0001); // the "shape_extra" morph is third, and is always 0.0
assert!((keyframes[4] - 0.0).abs() < 0.0001);
assert!((keyframes[3] + 0.4).abs() < 0.0001); assert!((keyframes[3] + 0.4).abs() < 0.0001);
assert!((keyframes[5] - 0.0).abs() < 0.0001);
} }
} }