mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
bvh model is animating, now I have to retarget
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -45,6 +45,7 @@ wasm = [
|
||||
"dep:web-sys",
|
||||
"bevy_rapier3d/wasm-bindgen",
|
||||
]
|
||||
desktop = []
|
||||
|
||||
[dependencies.bevy]
|
||||
workspace = true
|
||||
|
||||
+717
-1413
File diff suppressed because it is too large
Load Diff
+118
-41
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user