Skip to content

Commit

Permalink
Updates documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumeblanc committed Apr 22, 2024
1 parent 062df66 commit d3accce
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 16 deletions.
26 changes: 26 additions & 0 deletions samples/motion_playback/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,34 @@

## Description

Extracting root motion is the process of capturing character motion (translation and rotation) from an animation. The purpose is to re-apply motion at runtime to drive the character and its collision capsule. This allows the capsule (responsible for physical collisions) to follow precisely the character, even if it move during the animation. Furthermore it also allows to animate motion with varying speeds.

## Concept

The sample uses animation and motion tracks converted using *2ozz tools, relying itself on `ozz::animation::offline::MotionExtractor`.
The motion track is composed of:
- A translation track, built from the xz projection of the root joint.
- A rotation track, built from the yaw only movement of the root joint. Motion extractor loop option is also activated to ensure animation begin and end rotation matches.

*2ozz removed (ie: baked) the motion from the animation, so it can be applied at runtime.

At runtime, the position and rotation are sampled from the motion tracks each frame. They are accumulated to move the character transform (by delta motion each frame), allowing to continue moving when the animation loops.
The sample uses `ozz::sample::MotionAccumulator` and `ozz::sample::MotionSampler` utilities to help with the complexity of managing loops.

## Sample usage

The sample allows to activate / deactivate usage of motion tracks. Deactivating motion tracks shows the baked animation only.

The sample exposes `ozz::sample::MotionAccumulator` capability of applying a rotation to the path.

Finally, different options allows to render the motion track/path, as well as character trace.

## Implementation

1. Load the skeleton and tha animation with root motion extracted. See "playback" sample for more details.
2. Load position (ozz::animation::Float3Track) and rotation (ozz::animation::QuaternionTrack) tracks from the file exported by *2ozz tool.
3. Sample the animation local-space transforms and convert them to model-space.
4. Uses animation sampling time/ratio to sample also the motion tracks.
5. Accumulate motion using `ozz::sample::MotionAccumulator` utility. It automatically handles animation loops.
6. The rotation to apply this frame is computed from the angular velocity and frame duration.
6. Get current transform from the accumulator. Convert it to a Float4x4 matrix to render the character at this location.
35 changes: 19 additions & 16 deletions samples/motion_playback/sample_motion_playback.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,13 @@ class MotionPlaybackSampleApplication : public ozz::sample::Application {
return false;
}

// Reading motion tracks.
if (!ozz::sample::LoadMotionTrack(OPTIONS_motion, &motion_track_)) {
// Skeleton and animation needs to match.
if (skeleton_.num_joints() != animation_.num_tracks()) {
return false;
}

// Skeleton and animation needs to match.
if (skeleton_.num_joints() != animation_.num_tracks()) {
// Reading motion tracks.
if (!ozz::sample::LoadMotionTrack(OPTIONS_motion, &motion_track_)) {
return false;
}

Expand All @@ -189,6 +189,7 @@ class MotionPlaybackSampleApplication : public ozz::sample::Application {
virtual void OnDestroy() {}

virtual bool OnGui(ozz::sample::ImGui* _im_gui) {
char label[64];
// Exposes animation runtime playback controls.
{
static bool open = true;
Expand All @@ -204,7 +205,11 @@ class MotionPlaybackSampleApplication : public ozz::sample::Application {
if (open) {
_im_gui->DoCheckBox("Use motion position", &apply_motion_position_);
_im_gui->DoCheckBox("Use motion rotation", &apply_motion_rotation_);
if (_im_gui->DoButton("Reset accumulator")) {
std::snprintf(label, sizeof(label), "Angular vel: %.0f deg/s",
angular_velocity_ * 180.f / ozz::math::kPi);
_im_gui->DoSlider(label, -ozz::math::kPi_2, ozz::math::kPi_2,
&angular_velocity_);
if (_im_gui->DoButton("Teleport")) {
motion_sampler_.Teleport(ozz::math::Transform::identity());
}
}
Expand All @@ -213,36 +218,31 @@ class MotionPlaybackSampleApplication : public ozz::sample::Application {
static bool open = true;
ozz::sample::ImGui::OpenClose oc(_im_gui, "Motion display", &open);
if (open) {
char label[64];
_im_gui->DoCheckBox("Show box", &show_box_);

_im_gui->DoCheckBox("Show trace", &show_trace_);
std::snprintf(label, sizeof(label), "Trace size: %d", trace_size_);
_im_gui->DoSlider(label, 100, 2000, &trace_size_);
_im_gui->DoSlider(label, 100, 2000, &trace_size_, 2.f);

_im_gui->DoCheckBox("Show motion", &show_motion_);
_im_gui->DoCheckBox("Floating display", &floating_display_);
_im_gui->DoCheckBox("Floating display", &floating_display_,
show_motion_);

std::snprintf(label, sizeof(label), "Motion before: %.0f%%",
floating_before_ * 100.f);
_im_gui->DoSlider(label, 0.f, 3.f, &floating_before_, 1.f,
floating_display_);
floating_display_ && show_motion_);
std::snprintf(label, sizeof(label), "Motion after: %.0f%%",
floating_after_ * 100.f);
_im_gui->DoSlider(label, 0.f, 3.f, &floating_after_, 1.f,
floating_display_);

std::snprintf(label, sizeof(label), "Angular vel: %.0f deg/s",
angular_velocity_ * 180.f / ozz::math::kPi);
_im_gui->DoSlider(label, -ozz::math::kPi_2, ozz::math::kPi_2,
&angular_velocity_);
floating_display_ && show_motion_);
}
}
return true;
}

virtual void GetSceneBounds(ozz::math::Box* _bound) const {
ozz::sample::ComputePostureBounds(make_span(models_), transform_, _bound);
*_bound = TransformBox(transform_, bounding_);
}

private:
Expand Down Expand Up @@ -274,6 +274,9 @@ class MotionPlaybackSampleApplication : public ozz::sample::Application {
// Buffer of model space matrices.
ozz::vector<ozz::math::Float4x4> models_;

// Character bounding box.
const ozz::math::Box bounding_{{-.3f, 0.f, -.2f}, {.3f, 1.8f, .2f}};

// GUI options to apply root motion.
bool apply_motion_position_ = true;
bool apply_motion_rotation_ = true;
Expand Down

0 comments on commit d3accce

Please sign in to comment.