mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
checkpoint
This commit is contained in:
+158
-105
@@ -13,13 +13,14 @@ use bevy::{
|
||||
utils::hashbrown::HashMap,
|
||||
};
|
||||
use bevy_inspector_egui::egui::TextBuffer;
|
||||
use bevy_mod_picking::prelude::EntityEvent;
|
||||
use bevy_rapier3d::parry::transformation;
|
||||
use studio_bvh::{frames::Frame, joint};
|
||||
|
||||
mod error;
|
||||
mod loader;
|
||||
|
||||
use crate::scene::SceneState;
|
||||
use crate::{debug::print_mat3, scene::SceneState};
|
||||
|
||||
use self::loader::BvhLoader;
|
||||
|
||||
@@ -31,7 +32,10 @@ impl Plugin for BvhPlugin {
|
||||
.register_asset_loader(BvhLoader)
|
||||
.add_systems(Update, animate_bvh.run_if(in_state(SceneState::Active)))
|
||||
.register_type::<BvhJoint>()
|
||||
.register_type::<BvhAnim>();
|
||||
.register_type::<BvhAnim>()
|
||||
//Events
|
||||
.add_event::<UpdateBVHAnim>()
|
||||
.add_systems(PreUpdate, update_bvh_anim);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +53,8 @@ pub struct BvhAnim {
|
||||
should_play: bool,
|
||||
frame: usize,
|
||||
#[reflect(ignore)]
|
||||
retarget: Option<RetargetMap>,
|
||||
#[reflect(ignore)]
|
||||
timer: Timer,
|
||||
#[reflect(ignore)]
|
||||
last_frame: usize,
|
||||
@@ -99,49 +105,51 @@ fn apply_frame<T: ReadOnlyWorldQuery>(
|
||||
return;
|
||||
};
|
||||
|
||||
let joint_data = bvh_file
|
||||
.get_joint(joint_entity.joint.0)
|
||||
.expect("Invalid BVH format: the joint index is out of bounds");
|
||||
if let Some(joint) = joint_entity.joint {
|
||||
let joint_data = bvh_file
|
||||
.get_joint(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();
|
||||
//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();
|
||||
|
||||
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()]
|
||||
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(),
|
||||
);
|
||||
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
|
||||
@@ -171,10 +179,9 @@ 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 joint: Option<&'static BvhJoint>,
|
||||
pub children: Option<&'static mut Children>,
|
||||
pub transform: &'static mut Transform,
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -261,13 +268,25 @@ impl Command for SpawnBvhCommand {
|
||||
panic!("Could not create the BVH entity because the bvh file has no root joint")
|
||||
};
|
||||
|
||||
if let Some((skinned_model, RetargetMap)) = self.3 {
|
||||
let entity = world
|
||||
.query::<&Children>()
|
||||
.get(world, skinned_model)
|
||||
.unwrap();
|
||||
if let Some((skinned_model, retarget_map)) = self.3 {
|
||||
world.entity_mut(skinned_model).insert((
|
||||
BvhAnim {
|
||||
bvh: self.1,
|
||||
frame: 0,
|
||||
last_frame: 0,
|
||||
retarget: Some(retarget_map),
|
||||
should_play: true,
|
||||
timer: Timer::from_seconds(
|
||||
bvh.0.frame_time().as_secs_f32(),
|
||||
TimerMode::Repeating,
|
||||
),
|
||||
},
|
||||
Name::new("BVH Anim"),
|
||||
));
|
||||
|
||||
println!("Entity: {:?}", entity);
|
||||
world.send_event(UpdateBVHAnim {
|
||||
entity: skinned_model,
|
||||
});
|
||||
} else {
|
||||
let entity = world.spawn_empty().id();
|
||||
spawn_bvh_recursive(world, &entity, root);
|
||||
@@ -279,23 +298,112 @@ impl Command for SpawnBvhCommand {
|
||||
frame: 0,
|
||||
last_frame: 0,
|
||||
should_play: true,
|
||||
retarget: None,
|
||||
timer: Timer::from_seconds(
|
||||
bvh.0.frame_time().as_secs_f32(),
|
||||
TimerMode::Repeating,
|
||||
),
|
||||
},
|
||||
SpatialBundle::from_transform(self.2),
|
||||
Name::new("BVH Skeliton"),
|
||||
Name::new("BVH Anim"),
|
||||
))
|
||||
.add_child(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Update BVH anim Event Functions
|
||||
//==============================================================================
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct UpdateBVHAnim {
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
fn update_bvh_anim(
|
||||
mut commands: Commands,
|
||||
mut bvh_anims: Query<(Entity, &BvhAnim, Option<&Children>)>,
|
||||
mut update_events: EventReader<UpdateBVHAnim>,
|
||||
bvh_assets: Res<Assets<Bvh>>,
|
||||
) {
|
||||
for event in update_events.read() {
|
||||
// println!("Updating BVHs");
|
||||
// println!("{:?} | {:?}", event.entity, bvh_anims.single().0);
|
||||
// for anim in bvh_anims.iter() {
|
||||
// println!("Children {:?}", anim);
|
||||
// };
|
||||
|
||||
if let Ok(bvh_anim) = bvh_anims.get(event.entity) {
|
||||
let Some(bvh) = bvh_assets.get(bvh_anim.1.bvh.id()) else {
|
||||
continue;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn update_bvh_recursive(current_node: Entity, commands: &mut Commands, bvh_anim: &Bvh) {}
|
||||
|
||||
//==============================================================================
|
||||
// Utility Functions
|
||||
//==============================================================================
|
||||
|
||||
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]);
|
||||
|
||||
// Save the name of the joint
|
||||
let name = String::from_utf8_lossy(joint.data().name()).to_string();
|
||||
|
||||
world.entity_mut(*entity).insert((
|
||||
SpatialBundle::from_transform(transform),
|
||||
BvhJoint(joint.data().index()),
|
||||
Name::new(name),
|
||||
));
|
||||
|
||||
for child in joint.children() {
|
||||
let mut child_entity = world.spawn_empty().id();
|
||||
spawn_bvh_recursive(world, &child_entity, child);
|
||||
world.entity_mut(*entity).push_children(&[child_entity]);
|
||||
}
|
||||
}
|
||||
|
||||
// fn locate_rig(world: &mut World, current_entity: Entity) -> Option<Entity> {
|
||||
// let Ok(query) = world
|
||||
// .query::<(Option<&Children>, Option<&Name>)>()
|
||||
// .get(world, current_entity)
|
||||
// else {
|
||||
// return None;
|
||||
// };
|
||||
|
||||
// if let Some(name) = query.1 {
|
||||
// println!("Name: {}", name.as_str());
|
||||
// if name.as_str() == "Rig" {
|
||||
// return Some(current_entity);
|
||||
// }
|
||||
// }
|
||||
|
||||
// let children = if let Some(children) = query.0 {
|
||||
// children.iter().map(|x| x.clone()).collect::<Vec<_>>()
|
||||
// } else {
|
||||
// return None;
|
||||
// };
|
||||
|
||||
// for child in children.iter() {
|
||||
// println!("Child: {:?}", child);
|
||||
// if let Some(entity) = locate_rig(world, *child) {
|
||||
// return Some(entity);
|
||||
// }
|
||||
// }
|
||||
|
||||
// None
|
||||
// }
|
||||
|
||||
//==============================================================================
|
||||
// RetargetMap
|
||||
//==============================================================================
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RetargetMap {
|
||||
pub map: HashMap<String, String>,
|
||||
}
|
||||
@@ -375,58 +483,3 @@ impl RetargetMap {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Utility Functions
|
||||
//==============================================================================
|
||||
|
||||
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]);
|
||||
|
||||
// Save the name of the joint
|
||||
let name = String::from_utf8_lossy(joint.data().name()).to_string();
|
||||
|
||||
world.entity_mut(*entity).insert((
|
||||
SpatialBundle::from_transform(transform),
|
||||
BvhJoint(joint.data().index()),
|
||||
Name::new(name),
|
||||
));
|
||||
|
||||
for child in joint.children() {
|
||||
let mut child_entity = world.spawn_empty().id();
|
||||
spawn_bvh_recursive(world, &child_entity, child);
|
||||
world.entity_mut(*entity).push_children(&[child_entity]);
|
||||
}
|
||||
}
|
||||
|
||||
fn locate_rig(world: &mut World, current_entity: Entity) -> Option<Entity> {
|
||||
let Ok(query) = world
|
||||
.query::<(Option<&Children>, Option<&Name>)>()
|
||||
.get(world, current_entity)
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Some(name) = query.1 {
|
||||
println!("Name: {}", name.as_str());
|
||||
if name.as_str() == "Rig" {
|
||||
return Some(current_entity);
|
||||
}
|
||||
}
|
||||
|
||||
let children = if let Some(children) = query.0 {
|
||||
children.iter().map(|x| x.clone()).collect::<Vec<_>>()
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for child in children.iter() {
|
||||
println!("Child: {:?}", child);
|
||||
if let Some(entity) = locate_rig(world, *child) {
|
||||
return Some(entity);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
+1
-3
@@ -87,7 +87,7 @@ pub fn init(viewport_size: ViewportSize) {
|
||||
Startup,
|
||||
(move |mut cmd: Commands, mut ew: EventWriter<LoadSceneEvent>| {
|
||||
cmd.insert_resource(SkyboxId("gum_trees_4k".to_string()));
|
||||
ew.send(LoadSceneEvent("base-human-female".to_string()));
|
||||
ew.send(LoadSceneEvent("Alien".to_string()));
|
||||
})
|
||||
)
|
||||
// .add_systems(
|
||||
@@ -96,8 +96,6 @@ pub fn init(viewport_size: ViewportSize) {
|
||||
// )
|
||||
;
|
||||
|
||||
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
wasm::initialize();
|
||||
|
||||
|
||||
+13
-5
@@ -43,8 +43,8 @@ impl Plugin for ScenePlugin {
|
||||
init_scene_loading,
|
||||
tick_scene_loading.run_if(in_state(SceneState::Loading)),
|
||||
tick_scene_spawning.run_if(in_state(SceneState::Spawning)),
|
||||
).in_set(SceneSpawnerSystem)
|
||||
|
||||
)
|
||||
.in_set(SceneSpawnerSystem),
|
||||
)
|
||||
.add_systems(
|
||||
OnEnter(SceneState::Loading),
|
||||
@@ -158,11 +158,19 @@ fn spawn_test_bvh(
|
||||
mut commands: Commands,
|
||||
mut er_bvh_events: EventReader<AssetEvent<Bvh>>,
|
||||
r_bvh: Res<TestBvh>,
|
||||
mut asset_server : ResMut<AssetServer>
|
||||
mut asset_server: ResMut<AssetServer>,
|
||||
) {
|
||||
for event in er_bvh_events.read() {
|
||||
if matches!(event, AssetEvent::LoadedWithDependencies { .. }) {
|
||||
commands.spawn_skined_bvh_with_transform(&r_bvh.0, asset_server.load("gltf/base-human-female.gltf#Scene0"), RetargetMap::mocap_to_rigify(), Transform::from_scale(Vec3::splat(1.0)).with_translation(Vec3::new(0., 1.0, -0.024)));
|
||||
commands.spawn_skined_bvh_with_transform(
|
||||
&r_bvh.0,
|
||||
asset_server.load("gltf/base-human-female.gltf#Scene0"),
|
||||
RetargetMap::mocap_to_rigify(),
|
||||
Transform::from_scale(Vec3::splat(1.0))
|
||||
.with_translation(Vec3::new(0., 1.0, -0.024)),
|
||||
);
|
||||
|
||||
commands.spawn_bvh_with_transform(&r_bvh.0, Transform::from_xyz(0.0, 1.0, -0.024));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +184,7 @@ fn init_scene_loading(
|
||||
) {
|
||||
if let Some(id) = er.read().last() {
|
||||
let name = &**id;
|
||||
let path = format!("gltf/{name}.gltf");
|
||||
let path = format!("gltf/{name}.glb");
|
||||
|
||||
// Avoid trying to re-load this scene if it's already active
|
||||
if let Some(active_scene_path) =
|
||||
|
||||
Reference in New Issue
Block a user