mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-18 07:35:19 +00:00
Mixamo animation support (#37)
This PR adds support for Mixamo FBX imports (via backend conversion to glTF/glB) and some miscellaneous improvements to the animation systems. ### User-facing improvements * Retargeting math has been fixed to eliminate jittering issues * Retargeter can now handle animated bone translations when present (generally this is only used for root motion) ### Housekeeping / Code improvements * Animation-related components and system logic have been moved to a dedicated `anim` module and `AnimPlugin` * Retargeting stuff has been moved from the `bvh` module to `anim::retargeting` * Component-based solution for marking an entity as an animation retargeting source makes it easy to extend the retargeting functionality to new types of source animations ### Limitations Currently the code assumes that there will be at most one animation source at a time. That single animation (if present) will be retargeted to all other skeletons in the scene. A component-based solution for directing a specific target skeleton to use a specific source animation is possible, but will require some additional consideration around the implementation design for the read-only "viewer" modes. ### Test animations: * Hip-Hop Dancing (Mixamo): ?mode=viewer&mixamo=mocap/hip-hop-dancing.gltf * Shuffle (MocapNET): ?mode=viewer&bvh=mocap/shuffle.bvh * Scott (MocapNET): ?mode=viewer&bvh=mocap/scott.bvh * Scott 1 (MocapNET): ?mode=viewer&bvh=mocap/scott1.bvh
This commit is contained in:
+4
-73
@@ -6,22 +6,18 @@ use bevy::{
|
||||
tonemapping::Tonemapping,
|
||||
},
|
||||
gltf::Gltf,
|
||||
math::{vec2, Affine3A},
|
||||
math::vec2,
|
||||
pbr::ShadowFilteringMethod,
|
||||
prelude::*,
|
||||
render::{mesh::skinning::SkinnedMesh, primitives::Aabb, view::NoFrustumCulling},
|
||||
render::primitives::Aabb,
|
||||
scene::InstanceId,
|
||||
};
|
||||
|
||||
use space_editor::{
|
||||
prelude::PrefabMarker,
|
||||
space_prefab::{component::SceneAutoChild, editor_registry::EditorRegistryExt},
|
||||
};
|
||||
use space_editor::{prelude::PrefabMarker, space_prefab::component::SceneAutoChild};
|
||||
#[cfg(feature = "wasm")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use crate::{
|
||||
bvh::{Bvh, CommandsSpawnBvhExt},
|
||||
camera_controller::{CameraController, CameraControllerBundle},
|
||||
debug::DebugPoint,
|
||||
math::{Combinable, Extrema},
|
||||
@@ -40,14 +36,7 @@ impl Plugin for ScenePlugin {
|
||||
.add_state::<SceneState>()
|
||||
.add_event::<LoadSceneEvent>()
|
||||
.add_systems(Startup, initialize)
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
spawn_test_bvh.run_if(resource_exists::<TestBvh>()), // TODO
|
||||
init_scene_loading,
|
||||
)
|
||||
.in_set(SceneSpawnerSystem),
|
||||
)
|
||||
.add_systems(Update, init_scene_loading.in_set(SceneSpawnerSystem))
|
||||
.add_systems(
|
||||
OnEnter(SceneState::Active),
|
||||
(tag_scene_elements, frame_scene_in_view).in_set(SceneSpawnerSystem),
|
||||
@@ -71,10 +60,6 @@ impl Plugin for ScenePlugin {
|
||||
//setup default light
|
||||
app.add_systems(Startup, minimal_scene_setup);
|
||||
|
||||
app.editor_registry::<BindPoseLocal>();
|
||||
app.editor_registry::<BindPoseGlobal>();
|
||||
app.editor_registry::<InvBindPose>();
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
app.add_systems(
|
||||
Update,
|
||||
@@ -190,25 +175,8 @@ pub struct SceneData {
|
||||
pub scene_path: String,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct SkeletalJoint(pub Color);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct SceneRoot;
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
pub struct TestBvh(pub Handle<Bvh>); // TODO
|
||||
|
||||
#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct BindPoseLocal(pub Transform);
|
||||
|
||||
#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct BindPoseGlobal(pub Affine3A);
|
||||
|
||||
#[derive(Component, Clone, Copy, Debug, Default, Deref, DerefMut, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct InvBindPose(pub Affine3A);
|
||||
|
||||
fn initialize(mut cmd: Commands) {
|
||||
// Camera, graphics settings
|
||||
@@ -242,23 +210,6 @@ fn initialize(mut cmd: Commands) {
|
||||
));
|
||||
}
|
||||
|
||||
// TODO
|
||||
fn spawn_test_bvh(
|
||||
mut commands: Commands,
|
||||
mut er_bvh_events: EventReader<AssetEvent<Bvh>>,
|
||||
r_bvh: Res<TestBvh>,
|
||||
) {
|
||||
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.06))
|
||||
.with_translation(Vec3::new(0., 1.0, 0.524)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_scene_loading(mut cmd: Commands, mut er: EventReader<LoadSceneEvent>) {
|
||||
if let Some(id) = er.read().last() {
|
||||
info!("Loading scene: {}", id.0);
|
||||
@@ -299,8 +250,6 @@ fn tag_scene_elements(
|
||||
Without<NoMeshElement>,
|
||||
),
|
||||
>,
|
||||
q_skinned_meshes: Query<(Entity, &SkinnedMesh), Without<InitedKointSkinnedMesh>>,
|
||||
mut q_xforms: ParamSet<(TransformHelper, Query<&Transform>)>,
|
||||
mesh_entities: Query<Entity, With<Handle<Mesh>>>,
|
||||
) {
|
||||
for (e, children) in q_named_non_primitives.iter() {
|
||||
@@ -317,24 +266,6 @@ fn tag_scene_elements(
|
||||
cmd.entity(e).insert(NoMeshElement);
|
||||
}
|
||||
}
|
||||
|
||||
for (ent, skinned_mesh) in q_skinned_meshes.iter() {
|
||||
cmd.entity(ent)
|
||||
.insert(NoFrustumCulling)
|
||||
.insert(InitedKointSkinnedMesh);
|
||||
|
||||
for &joint in skinned_mesh.joints.iter() {
|
||||
let global_bind_pose = q_xforms.p0().compute_global_transform(joint).unwrap();
|
||||
let local_bind_pose = *q_xforms.p1().get(joint).unwrap();
|
||||
|
||||
cmd.entity(joint).insert((
|
||||
SkeletalJoint(Color::BLACK),
|
||||
BindPoseLocal(local_bind_pose),
|
||||
BindPoseGlobal(global_bind_pose.affine()),
|
||||
InvBindPose(global_bind_pose.affine().inverse()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_scene_in_view(
|
||||
|
||||
Reference in New Issue
Block a user