Skip to content

Commit

Permalink
Merge pull request #48 from SlimeYummy/feat/playback-demo
Browse files Browse the repository at this point in the history
playback demo
  • Loading branch information
SlimeYummy authored Mar 6, 2024
2 parents 8c2d35d + 33d3729 commit 7c3f14b
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 49 deletions.
106 changes: 57 additions & 49 deletions demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ mod blend;
mod playback;
mod two_bone_ik;

use bevy::prelude::*;
use bevy::pbr::NotShadowCaster;
use bevy::prelude::*;
use bevy::render::mesh::PrimitiveTopology;
use bevy::render::render_asset::RenderAssetUsages;
use bevy::tasks::futures_lite::future;
Expand Down Expand Up @@ -60,7 +60,7 @@ impl OzzComponent {
self.task = Some(task);
self.example = None;
}

fn load_next(&mut self) {
self.typ = (self.typ + 1) % OZZ_TYPES.len();
self.load();
Expand All @@ -79,11 +79,7 @@ impl OzzComponent {
#[derive(Component)]
struct BoneIndex(usize);

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>) {
let mut oc = OzzComponent::default();
oc.load();
commands.spawn(oc);
Expand Down Expand Up @@ -114,19 +110,22 @@ fn setup(
}

// camera
commands.spawn((Camera3dBundle {
transform: Transform::from_xyz(1.5, 1.0, 3.0).looking_at(Vec3::new(0.0, 1.0, -0.0), Vec3::Y),
..default()
}, FogSettings {
color: Color::rgba(0.35, 0.48, 0.66, 1.0),
directional_light_color: Color::rgba(1.0, 0.95, 0.85, 0.5),
directional_light_exponent: 30.0,
falloff: FogFalloff::from_visibility_colors(
15.0, // distance in world units up to which objects retain visibility (>= 5% contrast)
Color::rgb(0.35, 0.5, 0.66), // atmospheric extinction color (after light is lost due to absorption by atmospheric particles)
Color::rgb(0.8, 0.844, 1.0), // atmospheric inscattering color (light gained due to scattering from the sun)
),
}));
commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(1.5, 1.0, 3.0).looking_at(Vec3::new(0.0, 1.0, -0.0), Vec3::Y),
..default()
},
FogSettings {
color: Color::rgba(0.35, 0.48, 0.66, 1.0),
directional_light_color: Color::rgba(1.0, 0.95, 0.85, 0.5),
directional_light_exponent: 30.0,
falloff: FogFalloff::from_visibility_colors(
15.0, // distance in world units up to which objects retain visibility (>= 5% contrast)
Color::rgb(0.35, 0.5, 0.66), // atmospheric extinction color (after light is lost due to absorption by atmospheric particles)
Color::rgb(0.8, 0.844, 1.0), // atmospheric inscattering color (light gained due to scattering from the sun)
),
},
));

// Sun
commands.spawn(DirectionalLightBundle {
Expand All @@ -138,8 +137,7 @@ fn setup(
shadow_normal_bias: 0.9,
..default()
},
transform: Transform::from_xyz(-3.0, 2.0, -4.0)
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
transform: Transform::from_xyz(-3.0, 2.0, -4.0).looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
..default()
});

Expand Down Expand Up @@ -171,10 +169,15 @@ fn setup(
});
}

fn update_ozz_animation(keycode: Res<ButtonInput<KeyCode>>, mut oc_query: Query<&mut OzzComponent>, mut text_query: Query<&mut Text, With<DemoName>>, time: Res<Time>) {
fn update_ozz_animation(
keycode: Res<ButtonInput<KeyCode>>,
mut oc_query: Query<&mut OzzComponent>,
mut text_query: Query<&mut Text, With<DemoName>>,
time: Res<Time>,
) {
let mut oc = oc_query.iter_mut().last().unwrap(); // only one OzzComponent
oc.poll();

if keycode.just_pressed(KeyCode::Space) {
oc.load_next();

Expand All @@ -193,7 +196,7 @@ fn update_camera(mut query: Query<&mut Transform, With<Camera3d>>, oc_query: Que
// only one OzzComponent
let root = example.root();
let target = Vec3::new(root.w_axis.x, 1.0, root.w_axis.z);

let pos = target + Vec3::new(1.5, 1.0, 3.0);
for mut transform in query.iter_mut() {
*transform = Transform::from_translation(pos).looking_at(target, Vec3::Y);
Expand Down Expand Up @@ -305,31 +308,36 @@ fn draw_gizmos(gizmos: &mut Gizmos, trans: &OzzTransform) {
struct DemoName;

fn setup_ui(mut commands: Commands) {
commands.spawn((TextBundle::from_section(
format!("Demo: {}", OZZ_TYPES[0].1).as_str(),
TextStyle {
font_size: 32.0,
commands.spawn((
TextBundle::from_section(
format!("Demo: {}", OZZ_TYPES[0].1).as_str(),
TextStyle {
font_size: 32.0,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
left: Val::Px(5.0),
top: Val::Px(5.0),
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
left: Val::Px(5.0),
top: Val::Px(5.0),
..default()
}), DemoName));
}),
DemoName,
));

commands.spawn(TextBundle::from_section(
"Press space to switch demo",
TextStyle {
font_size: 32.0,
commands.spawn(
TextBundle::from_section(
"Press space to switch demo",
TextStyle {
font_size: 32.0,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
left: Val::Px(5.0),
top: Val::Px(40.0),
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
left: Val::Px(5.0),
top: Val::Px(40.0),
..default()
}));
}),
);
}
139 changes: 139 additions & 0 deletions demo/src/playback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use bevy::prelude::*;
use bevy::tasks::futures_lite::future::try_zip;
use ozz_animation_rs::math::*;
use ozz_animation_rs::*;
use std::sync::{Arc, RwLock};

use crate::base::*;

pub struct OzzPlayback {
skeleton: Arc<Skeleton>,
sample_job: ASamplingJob,
l2m_job: ALocalToModelJob,
models: Arc<RwLock<Vec<Mat4>>>,
bone_trans: Vec<OzzTransform>,
spine_trans: Vec<OzzTransform>,
}

impl OzzPlayback {
pub async fn new() -> Box<dyn OzzExample> {
let (mut ar_skeleton, mut ar_animation) = try_zip(
load_archive("/playback/skeleton.ozz"),
load_archive("/playback/animation.ozz"),
)
.await
.unwrap();

let skeleton = Arc::new(Skeleton::from_archive(&mut ar_skeleton).unwrap());
let animation = Arc::new(Animation::from_archive(&mut ar_animation).unwrap());

let mut oc = OzzPlayback {
skeleton: skeleton.clone(),
sample_job: SamplingJob::default(),
l2m_job: LocalToModelJob::default(),
models: Arc::new(RwLock::new(vec![Mat4::default(); skeleton.num_joints()])),
bone_trans: Vec::new(),
spine_trans: Vec::new(),
};

oc.sample_job.set_animation(animation.clone());
oc.sample_job.set_context(SamplingContext::new(animation.num_tracks()));
let sample_out = ozz_abuf(vec![SoaTransform::default(); skeleton.num_soa_joints()]);
oc.sample_job.set_output(sample_out.clone());

oc.l2m_job.set_skeleton(skeleton.clone());
oc.l2m_job.set_input(sample_out.clone());
oc.l2m_job.set_output(oc.models.clone());

let mut bone_count = 0;
let mut spine_count = 0;
for i in 0..skeleton.num_joints() {
let parent_id = skeleton.joint_parent(i);
if parent_id as i32 == SKELETON_NO_PARENT {
continue;
}
bone_count += 1;
spine_count += 1;
if skeleton.is_leaf(i as i16) {
spine_count += 1;
}
}

oc.bone_trans.reserve(bone_count);
oc.spine_trans.reserve(spine_count);
return Box::new(oc);
}
}

impl OzzExample for OzzPlayback {
fn root(&self) -> Mat4 {
return self.models.vec().unwrap()[0];
}

fn bone_trans(&self) -> &[OzzTransform] {
return &self.bone_trans;
}

fn spine_trans(&self) -> &[OzzTransform] {
return &self.spine_trans;
}

fn update(&mut self, time: Time) {
let duration = self.sample_job.animation().unwrap().duration();
let ratio = (time.elapsed_seconds() % duration) / duration;
self.sample_job.set_ratio(ratio);
self.sample_job.run().unwrap();
self.l2m_job.run().unwrap();

self.bone_trans.clear();
self.spine_trans.clear();

let modals = self.models.vec().unwrap();
for (i, current) in modals.iter().enumerate() {
let parent_id = self.skeleton.joint_parent(i);
if parent_id as i32 == SKELETON_NO_PARENT {
continue;
}
let parent = &modals[parent_id as usize];

let current_pos = current.w_axis.xyz();
let parent_pos = parent.w_axis.xyz();
let scale: f32 = (current_pos - parent_pos).length();

let bone_dir = (current_pos - parent_pos).normalize();
let dot1 = Vec3::dot(bone_dir, parent.x_axis.xyz());
let dot2 = Vec3::dot(bone_dir, parent.z_axis.xyz());
let binormal = if dot1.abs() < dot2.abs() {
parent.x_axis.xyz()
} else {
parent.z_axis.xyz()
};

let bone_rot_y = Vec3::cross(binormal, bone_dir).normalize();
let bone_rot_z = Vec3::cross(bone_dir, bone_rot_y).normalize();
let bone_rot = Quat::from_mat3(&Mat3::from_cols(bone_dir, bone_rot_y, bone_rot_z));

self.bone_trans.push(OzzTransform {
scale: scale,
rotation: bone_rot,
position: parent_pos,
});

let parent_rot = Quat::from_mat4(parent);
self.spine_trans.push(OzzTransform {
scale: scale,
rotation: parent_rot,
position: parent_pos,
});

if self.skeleton.is_leaf(i as i16) {
let current_rot = Quat::from_mat4(current);
self.spine_trans.push(OzzTransform {
scale: scale,
rotation: current_rot,
position: current_pos,
});
}
}
}
}

0 comments on commit 7c3f14b

Please sign in to comment.