loading animation

This commit is contained in:
Lee-Orr
2024-02-08 19:01:18 -05:00
parent 5ce86b6f9b
commit 725a56aa5a
5 changed files with 52 additions and 12 deletions
+18
View File
@@ -1,7 +1,10 @@
#![allow(clippy::type_complexity)]
use bevy::{ use bevy::{
pbr::{CascadeShadowConfigBuilder, DirectionalLightShadowMap}, pbr::{CascadeShadowConfigBuilder, DirectionalLightShadowMap},
prelude::*, prelude::*,
}; };
use bevy_facial_mocap::{CSVAnimationLoader, CSVAnimationLoaderSettings};
use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_inspector_egui::quick::WorldInspectorPlugin;
fn main() { fn main() {
@@ -9,10 +12,15 @@ fn main() {
.insert_resource(DirectionalLightShadowMap { size: 4096 }) .insert_resource(DirectionalLightShadowMap { size: 4096 })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_plugins(WorldInspectorPlugin::new()) .add_plugins(WorldInspectorPlugin::new())
.init_asset_loader::<CSVAnimationLoader>()
.add_systems(Startup, setup) .add_systems(Startup, setup)
.add_systems(Update, setup_animation)
.run(); .run();
} }
#[derive(Component)]
struct AnimationRunning(Handle<AnimationClip>);
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera3dBundle { commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y), transform: Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
@@ -42,3 +50,13 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..default() ..default()
}); });
} }
fn setup_animation(mut commands: Commands, asset_server: Res<AssetServer>, mut players: Query<Entity, (With<MorphWeights>, Without<AnimationRunning>)>) {
for entity in &mut players {
let handle = asset_server.load_with_settings("20240205_shapekey_BevyImplementationFaceCap_5/shapekey_BevyImplementationFaceCap_5_ScottiPhone_raw.morph_anim.csv", |s: &mut CSVAnimationLoaderSettings| { s.0.parts = vec![Name::new("pascal_Head")]; });
let mut player = AnimationPlayer::default();
player.play(handle.clone()).repeat();
commands.entity(entity).insert((AnimationRunning(handle), player));
}
}
+34 -12
View File
@@ -1,11 +1,9 @@
use std::{num::ParseFloatError, str::FromStr}; use std::{num::ParseFloatError, str::FromStr};
use bevy::{ use bevy::{
animation::{AnimationClip, EntityPath, Keyframes, VariableCurve}, animation::{self, AnimationClip, EntityPath, Keyframes, VariableCurve}, asset::{meta::Settings, Asset, AssetLoader, AsyncReadExt}, core::Name, reflect::Reflect
asset::{Asset, AssetLoader, AsyncReadExt},
reflect::Reflect,
}; };
use serde::{Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[derive( #[derive(
Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Reflect, Default, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Reflect, Default,
@@ -222,10 +220,10 @@ impl From<CSVAnimation> for VariableCurve {
} }
} }
impl From<CSVAnimation> for AnimationClip { impl CSVAnimation {
fn from(val: CSVAnimation) -> Self { fn generate_clip(self, path: &EntityPath) -> AnimationClip {
let mut clip = Self::default(); let mut clip = AnimationClip::default();
clip.add_curve_to_path(EntityPath::default(), val.into()); clip.add_curve_to_path(path.clone(), self.into());
clip clip
} }
@@ -249,17 +247,38 @@ 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| Name::new(name)).collect() }))
}
}
impl AssetLoader for CSVAnimationLoader { impl AssetLoader for CSVAnimationLoader {
type Asset = AnimationClip; type Asset = AnimationClip;
type Settings = (); type Settings = CSVAnimationLoaderSettings;
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 {
@@ -270,7 +289,10 @@ impl AssetLoader for CSVAnimationLoader {
.map_err(CSVAnimationLoaderError::Io)?; .map_err(CSVAnimationLoaderError::Io)?;
let csv_animation = let csv_animation =
CSVAnimation::parse(&csv).map_err(CSVAnimationLoaderError::CSVParseError)?; CSVAnimation::parse(&csv).map_err(CSVAnimationLoaderError::CSVParseError)?;
Ok(csv_animation.into())
let animation = csv_animation.generate_clip(&settings.0);
Ok(animation)
}) })
} }
@@ -423,7 +445,7 @@ mod tests {
00:00:01:01.00, 0, 0, 0", 00:00:01:01.00, 0, 0, 0",
) )
.unwrap(); .unwrap();
let clip: AnimationClip = animation.into(); let clip: AnimationClip = animation.generate_clip(&EntityPath::default());
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::default())