mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-19 07:53:25 +00:00
Stablized bvh representation
This commit is contained in:
+39
-37
@@ -6,7 +6,7 @@ use bevy::{
|
||||
|
||||
use super::{
|
||||
error::{Anyhow, Error},
|
||||
Bvh, BvhJoint,
|
||||
Bvh,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -26,22 +26,24 @@ impl AssetLoader for BvhLoader {
|
||||
Box::pin(async move {
|
||||
let mut buf = vec![];
|
||||
reader.read_to_end(&mut buf).await.anyhow()?;
|
||||
let bvh = studio_bvh::from_bytes(&buf).anyhow()?;
|
||||
|
||||
// FIXME: This is algorithmically terrible
|
||||
let bvh = studio_bvh::from_bytes(&buf).anyhow()?;
|
||||
let all_joints = bvh.joints().map(|j| j.data().clone()).collect::<Vec<_>>();
|
||||
let joints = bvh
|
||||
.joints()
|
||||
.filter_map(|joint| {
|
||||
if joint.is_root() {
|
||||
Some(joint.data().clone().into_bvh_joint(&all_joints))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
// let all_joints = bvh.joints().map(|j| j.data().clone()).collect::<Vec<_>>();
|
||||
// let joints = bvh
|
||||
// .joints()
|
||||
// .filter_map(|joint| {
|
||||
// if joint.is_root() {
|
||||
// Some(joint.data().clone().into_bvh_joint(&all_joints))
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// })
|
||||
// .collect();
|
||||
|
||||
Ok(Bvh { joints })
|
||||
// bvh.frame_cursor().
|
||||
|
||||
Ok(Bvh(bvh))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,27 +52,27 @@ impl AssetLoader for BvhLoader {
|
||||
}
|
||||
}
|
||||
|
||||
trait IntoBvhJoint: Sized {
|
||||
fn into_bvh_joint(self, data: &[Self]) -> BvhJoint;
|
||||
}
|
||||
// trait IntoBvhJoint: Sized {
|
||||
// fn into_bvh_joint(self, data: &[Self]) -> BvhJoint;
|
||||
// }
|
||||
|
||||
impl IntoBvhJoint for studio_bvh::JointData {
|
||||
fn into_bvh_joint(self, data: &[Self]) -> BvhJoint {
|
||||
BvhJoint {
|
||||
name: String::from_utf8_lossy(self.name()).into(),
|
||||
transform: Transform::from_translation((*self.offset()).into()),
|
||||
children: data
|
||||
.iter()
|
||||
.filter_map(|joint| {
|
||||
joint.parent_index().and_then(|idx| {
|
||||
if idx == self.index() {
|
||||
Some(joint.clone().into_bvh_joint(data))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl IntoBvhJoint for studio_bvh::JointData {
|
||||
// fn into_bvh_joint(self, data: &[Self]) -> BvhJoint {
|
||||
// BvhJoint {
|
||||
// name: String::from_utf8_lossy(self.name()).into(),
|
||||
// transform: Transform::from_translation((*self.offset()).into()),
|
||||
// children: data
|
||||
// .iter()
|
||||
// .filter_map(|joint| {
|
||||
// joint.parent_index().and_then(|idx| {
|
||||
// if idx == self.index() {
|
||||
// Some(joint.clone().into_bvh_joint(data))
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// .collect(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
+115
-12
@@ -1,4 +1,5 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::{prelude::*, ecs::system::{Command, EntityCommands}, asset::AsyncReadExt};
|
||||
use studio_bvh::joint;
|
||||
|
||||
mod error;
|
||||
mod loader;
|
||||
@@ -10,21 +11,123 @@ pub struct BvhPlugin;
|
||||
impl Plugin for BvhPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_asset::<Bvh>()
|
||||
.init_asset::<BvhJoint>()
|
||||
.register_asset_loader(BvhLoader);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Asset, TypePath, Debug)]
|
||||
pub struct Bvh {
|
||||
pub joints: Vec<BvhJoint>,
|
||||
//==============================================================================
|
||||
// Bvh Asset
|
||||
//==============================================================================
|
||||
|
||||
#[derive(Clone, Debug, Default, Asset, TypePath)]
|
||||
pub struct Bvh(studio_bvh::Bvh);
|
||||
|
||||
//==============================================================================
|
||||
// Bvh Anim Component
|
||||
//==============================================================================
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct BvhAnim {
|
||||
pub bvh : Handle<Bvh>,
|
||||
pub frame : usize,
|
||||
}
|
||||
|
||||
#[derive(Asset, TypePath, Debug, Clone)]
|
||||
pub struct BvhJoint {
|
||||
pub name: String,
|
||||
/// Local transform
|
||||
pub transform: Transform,
|
||||
/// Direct children of this joint
|
||||
pub children: Vec<BvhJoint>,
|
||||
//==============================================================================
|
||||
// Bvh Anim Component
|
||||
//==============================================================================
|
||||
|
||||
#[derive(Debug, Component)]
|
||||
pub struct BvhJoint;
|
||||
|
||||
//==============================================================================
|
||||
// Commands Plugin
|
||||
//==============================================================================
|
||||
|
||||
pub trait CommandsSpawnBvhExt {
|
||||
fn spawn_bvh(&mut self, asset : &Handle<Bvh>) -> Entity;
|
||||
|
||||
fn spawn_bvh_with_transform(&mut self, asset : &Handle<Bvh>, transform : Transform) -> Entity;
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
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
|
||||
));
|
||||
entity
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpawnBvhCommand(Entity, f32, Handle<Bvh>);
|
||||
|
||||
impl Command for SpawnBvhCommand {
|
||||
fn apply(self, world: &mut World) {
|
||||
let bvh = {
|
||||
let Some(bvh) = world.get_resource::<Assets<Bvh>>().unwrap().get(self.2)
|
||||
else { panic!("Could not create the BVH entity because the bvh file has not been loaded yet") };
|
||||
|
||||
bvh.clone()
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// 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]);
|
||||
|
||||
// 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,
|
||||
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]);
|
||||
};
|
||||
}
|
||||
+24
-2
@@ -2,13 +2,14 @@ use std::fmt;
|
||||
|
||||
use bevy::{prelude::*, window::PrimaryWindow};
|
||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||
use bevy_mod_picking::debug::DebugPickingMode;
|
||||
use bevy_mod_picking::debug::{DebugPickingMode, self};
|
||||
use bevy_rapier3d::na::Quaternion;
|
||||
|
||||
use crate::{
|
||||
camera_controller::{CameraController, CameraMotionSystem},
|
||||
input::{Action, InputAction, Lifecycle},
|
||||
scene::SkeletalJoint,
|
||||
MainCamera,
|
||||
MainCamera, bvh::BvhJoint,
|
||||
};
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
@@ -36,6 +37,7 @@ impl Plugin for DebugPlugin {
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
debug_bvh_model,
|
||||
toggle_debug_mode,
|
||||
update_debug_picking_mode.run_if(resource_changed::<DebugMode>()),
|
||||
update_gizmo_line_thickness,
|
||||
@@ -47,6 +49,26 @@ impl Plugin for DebugPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_bvh_model(
|
||||
mut gizmos: Gizmos,
|
||||
bvh_joints : Query<(&GlobalTransform, Option<&Children>), With<BvhJoint>>,
|
||||
debug_mode : Res<DebugMode>,
|
||||
) {
|
||||
if debug_mode.0 {
|
||||
for (transform, children) in bvh_joints.iter() {
|
||||
gizmos.sphere(transform.translation(), Quat::IDENTITY, 0.01, Color::TEAL);
|
||||
|
||||
if let Some(children) = children {
|
||||
for child in children.iter() {
|
||||
if let Ok((child_transform, _)) = bvh_joints.get(child.clone()) {
|
||||
gizmos.line(transform.translation(), child_transform.translation(), Color::RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_debug_mode(mut input: EventReader<InputAction>, mut r_debug: ResMut<DebugMode>) {
|
||||
if input
|
||||
.read()
|
||||
|
||||
+36
-34
@@ -17,7 +17,7 @@ use bevy::{
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use crate::{
|
||||
bvh::{Bvh, BvhJoint},
|
||||
bvh::{Bvh, BvhJoint, CommandsSpawnBvhExt},
|
||||
camera_controller::{CameraController, CameraControllerBundle},
|
||||
debug::DebugPoint,
|
||||
math::{Combinable, Extrema},
|
||||
@@ -155,52 +155,54 @@ fn initialize(mut cmd: Commands, r_assets: Res<AssetServer>) {
|
||||
|
||||
// TODO
|
||||
fn spawn_test_bvh(
|
||||
mut cmd: Commands,
|
||||
mut commands: Commands,
|
||||
mut er_bvh_events: EventReader<AssetEvent<Bvh>>,
|
||||
r_bvh: Res<TestBvh>,
|
||||
ra_bvh: Res<Assets<Bvh>>,
|
||||
) {
|
||||
for event in er_bvh_events.read() {
|
||||
if matches!(event, AssetEvent::LoadedWithDependencies { .. }) {
|
||||
let bvh = ra_bvh.get(&**r_bvh).unwrap();
|
||||
for joint in bvh.joints.iter() {
|
||||
let scale = Vec3::splat(0.01);
|
||||
let offset = vec3(0., 0.849, -0.024);
|
||||
commands.spawn_bvh_with_transform(&r_bvh.0, Transform::from_scale(Vec3::splat(0.01)).with_translation(Vec3::new(0., 0.849, -0.024)));
|
||||
|
||||
let mut parent = cmd.spawn((
|
||||
Name::new("BVH Skeleton"),
|
||||
SpatialBundle::from_transform(Transform {
|
||||
rotation: default(),
|
||||
translation: offset,
|
||||
scale,
|
||||
}),
|
||||
));
|
||||
let parent_ent = parent.id();
|
||||
info!("SPAWNED BVH")
|
||||
// let bvh = ra_bvh.get(&**r_bvh).unwrap();
|
||||
// for joint in bvh.joints.iter() {
|
||||
// let scale = Vec3::splat(0.01);
|
||||
// let offset = vec3(0., 0.849, -0.024);
|
||||
|
||||
spawn_joint(parent.commands(), joint, Some(parent_ent));
|
||||
}
|
||||
// let mut parent = cmd.spawn((
|
||||
// Name::new("BVH Skeleton"),
|
||||
// SpatialBundle::from_transform(Transform {
|
||||
// rotation: default(),
|
||||
// translation: offset,
|
||||
// scale,
|
||||
// }),
|
||||
// ));
|
||||
// let parent_ent = parent.id();
|
||||
|
||||
// spawn_joint(parent.commands(), joint, Some(parent_ent));
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
fn spawn_joint(cmd: &mut Commands, joint: &BvhJoint, parent: Option<Entity>) {
|
||||
let mut spawned = cmd.spawn((
|
||||
Name::new(joint.name.clone()),
|
||||
SpatialBundle::from_transform(joint.transform),
|
||||
SceneElement,
|
||||
SkeletalJoint(Color::CYAN),
|
||||
));
|
||||
let spawned_ent = spawned.id();
|
||||
// // TODO
|
||||
// fn spawn_joint(cmd: &mut Commands, joint: &BvhJoint, parent: Option<Entity>) {
|
||||
// let mut spawned = cmd.spawn((
|
||||
// Name::new(joint.name.clone()),
|
||||
// SpatialBundle::from_transform(joint.transform),
|
||||
// SceneElement,
|
||||
// SkeletalJoint(Color::CYAN),
|
||||
// ));
|
||||
// let spawned_ent = spawned.id();
|
||||
|
||||
if let Some(parent) = parent {
|
||||
spawned.set_parent(parent);
|
||||
}
|
||||
// if let Some(parent) = parent {
|
||||
// spawned.set_parent(parent);
|
||||
// }
|
||||
|
||||
for child in joint.children.iter() {
|
||||
spawn_joint(spawned.commands(), child, Some(spawned_ent));
|
||||
}
|
||||
}
|
||||
// for child in joint.children.iter() {
|
||||
// spawn_joint(spawned.commands(), child, Some(spawned_ent));
|
||||
// }
|
||||
// }
|
||||
|
||||
fn init_scene_loading(
|
||||
mut cmd: Commands,
|
||||
|
||||
Reference in New Issue
Block a user