bvh model is animating, now I have to retarget

This commit is contained in:
Brooks Palin
2024-01-02 14:33:08 -07:00
parent 744fd75192
commit 55673859e9
6 changed files with 850 additions and 1459 deletions
+11
View File
@@ -678,6 +678,17 @@ impl Bvh {
pub fn frame_cursor(&mut self) -> FrameCursor<'_> {
From::from(self)
}
pub fn get_joint(&self, index: usize) -> Option<Joint<'_>> {
if index < self.joints.len() {
Some(Joint {
index,
joints: &self.joints,
})
} else {
None
}
}
}
impl Default for Bvh {
+1
View File
@@ -45,6 +45,7 @@ wasm = [
"dep:web-sys",
"bevy_rapier3d/wasm-bindgen",
]
desktop = []
[dependencies.bevy]
workspace = true
File diff suppressed because it is too large Load Diff
+118 -41
View File
@@ -1,5 +1,7 @@
use bevy::{prelude::*, ecs::system::{Command, EntityCommands}, asset::AsyncReadExt};
use studio_bvh::joint;
use std::backtrace::Backtrace;
use bevy::{prelude::*, ecs::{system::{Command, EntityCommands, SystemParam}, query::{WorldQuery, ReadOnlyWorldQuery}}, asset::AsyncReadExt, transform::commands};
use studio_bvh::{joint, frames::Frame};
mod error;
mod loader;
@@ -11,7 +13,12 @@ pub struct BvhPlugin;
impl Plugin for BvhPlugin {
fn build(&self, app: &mut App) {
app.init_asset::<Bvh>()
.register_asset_loader(BvhLoader);
.register_asset_loader(BvhLoader)
.add_systems(Update, animate_bvh)
.register_type::<BvhJoint>()
.register_type::<BvhAnim>()
;
}
}
@@ -26,18 +33,103 @@ pub struct Bvh(studio_bvh::Bvh);
// Bvh Anim Component
//==============================================================================
#[derive(Component, Debug)]
#[derive(Component, Debug, Reflect)]
pub struct BvhAnim {
pub bvh : Handle<Bvh>,
pub frame : usize,
#[reflect(ignore)]
bvh : Handle<Bvh>,
should_play : bool,
frame : usize,
#[reflect(ignore)]
timer : Timer,
#[reflect(ignore)]
last_frame : usize,
}
pub fn animate_bvh(
mut command : Commands,
mut bvh_anims : Query<(Entity, &mut BvhAnim, &mut Transform, &mut Children)>,
mut bvh_joints : Query<JointQuery, Without<BvhAnim>>,
bvh_assets : Res<Assets<Bvh>>,
time : Res<Time>
) {
for (entity, mut anim, transform, children) in bvh_anims.iter_mut() {
let bvh = &bvh_assets.get(anim.bvh.clone()).expect("Could not animate the BVH because the bvh file has not been loaded yet").0;
if anim.should_play {
anim.timer.tick(time.delta());
if anim.timer.finished() {
anim.frame = (anim.frame + 1) % bvh.frames().len();
anim.timer.reset();
// command.entity(entity).remove::<BvhAnim>();
}
}
if anim.last_frame != anim.frame {
let frame = bvh.frames().nth(anim.frame).expect("Invalid BVH format: the frame index is out of bounds");
for child in children.iter() {
apply_frame(&mut bvh_joints, *child, &frame, &bvh);
}
anim.last_frame = anim.frame;
}
}
}
fn apply_frame<T : ReadOnlyWorldQuery>(joint_query : &mut Query<JointQuery, T>, current_joint : Entity, frame : &Frame, bvh_file : &studio_bvh::Bvh) {
let Ok(mut joint_entity) = joint_query.get_mut(current_joint)
else { return; };
let joint_data = bvh_file.get_joint(joint_entity.joint.0).expect("Invalid BVH format: the joint index is out of bounds");
//new Positions and rotations
let mut new_pos = joint_entity.transform.translation;
let mut new_rot : Vec3 = joint_entity.transform.rotation.to_euler(EulerRot::ZXY).into();
info!("Joint: {} {} {}", joint_entity.joint.0, String::from_utf8_lossy(joint_data.data().name()), joint_entity.name);
for channel in joint_data.channels() {
// info!("Channel {}: {:?} : {}", channel.motion_index(), channel.channel_type(), frame.as_slice()[channel.motion_index()]);
match channel.channel_type() {
studio_bvh::ChannelType::PositionX => new_pos.x = frame.as_slice()[channel.motion_index()],
studio_bvh::ChannelType::PositionY => new_pos.y = frame.as_slice()[channel.motion_index()],
studio_bvh::ChannelType::PositionZ => new_pos.z = frame.as_slice()[channel.motion_index()],
studio_bvh::ChannelType::RotationX => new_rot.x = frame.as_slice()[channel.motion_index()],
studio_bvh::ChannelType::RotationY => new_rot.y = frame.as_slice()[channel.motion_index()],
studio_bvh::ChannelType::RotationZ => new_rot.z = frame.as_slice()[channel.motion_index()],
}
}
joint_entity.transform.translation = new_pos;
joint_entity.transform.rotation = Quat::from_euler(EulerRot::ZXY, new_rot.z.to_radians(), new_rot.x.to_radians(), new_rot.y.to_radians());
if joint_entity.children.is_some() {
let children = joint_entity.children.as_mut().unwrap().iter().map(Entity::clone).collect::<Vec<_>>();
drop(joint_data);
drop(joint_entity);
for child in children {
apply_frame(joint_query, child, frame, bvh_file);
}
}
}
//==============================================================================
// Bvh Anim Component
//==============================================================================
#[derive(Debug, Component)]
pub struct BvhJoint;
#[derive(Debug, Component, Reflect)]
pub struct BvhJoint(usize);
#[derive(Debug, WorldQuery)]
#[world_query(mutable)]
pub struct JointQuery {
pub name : &'static Name,
pub joint : &'static BvhJoint,
pub transform : &'static mut Transform,
pub children : Option<&'static mut Children>,
}
//==============================================================================
// Commands Plugin
@@ -52,36 +144,23 @@ pub trait CommandsSpawnBvhExt {
impl <'w, 's> CommandsSpawnBvhExt for Commands<'w, 's> {
fn spawn_bvh(&mut self, asset : &Handle<Bvh>) -> Entity {
let entity = self.spawn_empty().id();
self.add(SpawnBvhCommand(entity, 1.0, asset.clone()));
self.entity(entity).insert(BvhAnim {
bvh : asset.clone(),
frame : 0,
});
self.add(SpawnBvhCommand(entity, asset.clone(), Transform::default()));
entity
}
fn spawn_bvh_with_transform(&mut self, asset : &Handle<Bvh>, transform : Transform) -> Entity {
let entity = self.spawn_empty().id();
self.add(SpawnBvhCommand(entity, 1.0, asset.clone()));
self.entity(entity).insert((
BvhAnim {
bvh : asset.clone(),
frame : 0,
},
transform
));
self.add(SpawnBvhCommand(entity, asset.clone(), transform));
entity
}
}
pub struct SpawnBvhCommand(Entity, f32, Handle<Bvh>);
pub struct SpawnBvhCommand(Entity, Handle<Bvh>, Transform);
impl Command for SpawnBvhCommand {
fn apply(self, world: &mut World) {
let bvh = {
let Some(bvh) = world.get_resource::<Assets<Bvh>>().unwrap().get(self.2)
let Some(bvh) = world.get_resource::<Assets<Bvh>>().unwrap().get(&self.1)
else { panic!("Could not create the BVH entity because the bvh file has not been loaded yet") };
bvh.clone()
@@ -90,7 +169,19 @@ impl Command for SpawnBvhCommand {
let Some(root) = bvh.0.root_joint()
else { panic!("Could not create the BVH entity because the bvh file has no root joint") };
spawn_bvh_recursive(world, &self.0, root);
let entity = world.spawn_empty().id();
spawn_bvh_recursive(world, &entity, root);
world.entity_mut(self.0).insert((
BvhAnim {
bvh : self.1,
frame : 0,
last_frame : 0,
should_play : true,
timer : Timer::from_seconds(bvh.0.frame_time().as_secs_f32(), TimerMode::Repeating),
},
SpatialBundle::from_transform(self.2),
Name::new("BVH Skeliton"),
)).add_child(entity);
}
}
@@ -98,20 +189,6 @@ impl Command for SpawnBvhCommand {
// Utility Functions
//==============================================================================
// fn spawn_bvh(commands : &mut Commands, asset : Handle<Bvh>, assets : &Res<Assets<Bvh>>) -> Option<Entity> {
// let Some(root) = bvh.0.root_joint()
// else { return None; };
// let tree = spawn_bvh_recursive(commands, &bvh.0, root);
// // commands.entity(tree).insert(BvhAnim {
// // bvh : bvh.id(),
// // frame : 0,
// // }
// // Some()
// }
fn spawn_bvh_recursive(world : &mut World, entity : &Entity, joint : studio_bvh::Joint) {
let offset = joint.data().offset();
let transform = Transform::from_xyz(offset[0], offset[1], offset[2]);
@@ -121,7 +198,7 @@ fn spawn_bvh_recursive(world : &mut World, entity : &Entity, joint : studio_bvh:
world.entity_mut(*entity).insert((
SpatialBundle::from_transform(transform),
BvhJoint,
BvhJoint(joint.data().index()),
Name::new(name)
));
+1 -1
View File
@@ -54,7 +54,7 @@ fn debug_bvh_model(
bvh_joints : Query<(&GlobalTransform, Option<&Children>), With<BvhJoint>>,
debug_mode : Res<DebugMode>,
) {
if debug_mode.0 {
if true {
for (transform, children) in bvh_joints.iter() {
gizmos.sphere(transform.translation(), Quat::IDENTITY, 0.01, Color::TEAL);
+2 -4
View File
@@ -150,7 +150,7 @@ fn initialize(mut cmd: Commands, r_assets: Res<AssetServer>) {
));
// TODO
cmd.insert_resource(TestBvh(r_assets.load("mocap/scott.bvh")));
cmd.insert_resource(TestBvh(r_assets.load("mocap/shuffle.bvh")));
}
// TODO
@@ -161,9 +161,7 @@ fn spawn_test_bvh(
) {
for event in er_bvh_events.read() {
if matches!(event, AssetEvent::LoadedWithDependencies { .. }) {
commands.spawn_bvh_with_transform(&r_bvh.0, Transform::from_scale(Vec3::splat(0.01)).with_translation(Vec3::new(0., 0.849, -0.024)));
info!("SPAWNED BVH")
commands.spawn_bvh_with_transform(&r_bvh.0, Transform::from_scale(Vec3::splat(0.06)).with_translation(Vec3::new(0., 1.0, -0.024)));
// let bvh = ra_bvh.get(&**r_bvh).unwrap();
// for joint in bvh.joints.iter() {
// let scale = Vec3::splat(0.01);