Skip to content

Commit

Permalink
Updates accumulator documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumeblanc committed Apr 20, 2024
1 parent fcd3b57 commit b7e8747
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 78 deletions.
96 changes: 22 additions & 74 deletions samples/framework/motion_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,24 +103,28 @@ bool SampleMotion(const MotionTrack& _tracks, float _ratio,
return true;
}

void MotionAccumulator::Update(const ozz::math::Transform& _new) {
return Update(_new, ozz::math::Quaternion::identity());
}

// Accumulates motion deltas (new transform - last).
void MotionAccumulator::Update(const ozz::math::Transform& _new,
const ozz::math::Quaternion& _rot) {
const ozz::math::Quaternion& _delta_rotation) {
// Accumulates rotation.
// Normalizes to avoid accumulating error.
accum_rotation = Normalize(accum_rotation * _rot);
rotation_accum_ = Normalize(rotation_accum_ * _delta_rotation);

// Computes delta translation.
const ozz::math::Float3 delta_p = _new.translation - last.translation;
current.translation =
current.translation + TransformVector(accum_rotation, delta_p);
current.translation + TransformVector(rotation_accum_, delta_p);

// Computes delta rotation.
const ozz::math::Quaternion delta_r =
Conjugate(last.rotation) * _new.rotation;
current.rotation =
Normalize(current.rotation * delta_r *
_rot); // Normalizes to avoid accumulating error.
_delta_rotation); // Normalizes to avoid accumulating error.

// Next time, delta will be computed from the _new transform.
last = _new;
Expand All @@ -134,12 +138,17 @@ void MotionAccumulator::Teleport(const ozz::math::Transform& _origin) {
// Resets current transform to new _origin
current = last = _origin;

accum_rotation = ozz::math::Quaternion::identity();
// Resets rotation accumulator.
rotation_accum_ = ozz::math::Quaternion::identity();
}

bool MotionSampler::Update(const MotionTrack& _motion, float _ratio,
int _loops) {
return Update(_motion, _ratio, _loops, ozz::math::Quaternion::identity());
}

// Updates the accumulator with a new motion sample.
bool MotionSampler::Update(const MotionTrack& _motion, float _ratio, int _loops,
const ozz::math::Quaternion& _rot) {
const ozz::math::Quaternion& _delta_rotation) {
ozz::math::Transform sample;

if (_loops != 0) {
Expand All @@ -154,7 +163,7 @@ bool MotionSampler::Update(const MotionTrack& _motion, float _ratio, int _loops,
if (!SampleMotion(_motion, _loops > 0 ? 1.f : 0.f, &sample)) {
return false;
}
local_accumulator.Update(sample, ozz::math::Quaternion::identity());
local_accumulator.Update(sample);

// Samples motion at the new origin.
if (!SampleMotion(_motion, _loops > 0 ? 0.f : 1.f, &sample)) {
Expand All @@ -168,12 +177,12 @@ bool MotionSampler::Update(const MotionTrack& _motion, float _ratio, int _loops,
if (!SampleMotion(_motion, _ratio, &sample)) {
return false;
}
local_accumulator.Update(sample, ozz::math::Quaternion::identity());
local_accumulator.Update(sample);

// Update "this" accumulator with the one accumulated during the loop(s).
// This way, _rot is applied to the whole motion, including what happened
// during the loop(s).
MotionAccumulator::Update(local_accumulator.current, _rot);
MotionAccumulator::Update(local_accumulator.current, _delta_rotation);

// Next time, delta will be computed from the new origin, aka after the
// loop.
Expand All @@ -185,12 +194,14 @@ bool MotionSampler::Update(const MotionTrack& _motion, float _ratio, int _loops,
return false;
}
// Apply motion
MotionAccumulator::Update(sample, _rot);
MotionAccumulator::Update(sample, _delta_rotation);
}

return true;
}

// Uses a MotionSampler to estimate past and future positions arount _at.
// This is a great test for the MotionSampler and MotionAccumulator.
bool DrawMotion(ozz::sample::Renderer* _renderer,
const MotionTrack& _motion_track, float _from, float _at,
float _to, float _step, const ozz::math::Float4x4& _transform,
Expand Down Expand Up @@ -243,68 +254,5 @@ bool DrawMotion(ozz::sample::Renderer* _renderer,
return success;
}

bool DrawMotion2(ozz::sample::Renderer* _renderer,
const MotionTrack& _motion_track, float _at, float _duration,
const ozz::math::Float4x4& _transform) {
if (_duration <= 0.f) {
return false;
}

// Clamps _at to [0, 1]
_at = ozz::math::Clamp(0.f, _at, 1.f);

// Find track current transform in order to correctly place the motion at
// character transform.
ozz::math::Transform at_transform;
SampleMotion(_motion_track, _at, &at_transform);
const auto transform =
_transform * Invert(ozz::math::Float4x4::FromAffine(at_transform));

// Samples points along the track.
ozz::vector<ozz::math::Float3> points;
auto sample = [&track = _motion_track.position, &points](float _t) {
ozz::math::Float3 point;
ozz::animation::Float3TrackSamplingJob sampler;
sampler.track = &track;
sampler.result = &point;
sampler.ratio = _t;
if (!sampler.Run()) {
return false;
}
points.push_back(point);
return true;
};

size_t at = 0;
const float step = 1.f / (_duration * 30.f); // 30Hz sampling
for (float t = 0.f; t < 1.f + step; t += step) {
if (t > _at && t <= _at + step) { // Inject a point at t = _at
at = points.size();
if (!sample(_at)) {
return false;
}
}
if (!sample(t)) {
return false;
}
}

// Draws from begin to _at (+1 to include _at)
const size_t end = points.size();
assert(at + 1 <= end);
if (!_renderer->DrawLineStrip(ozz::span(points.data(), at + 1),
ozz::sample::kGreen, transform)) {
return false;
}

// Draws from _at to end
if (!_renderer->DrawLineStrip(ozz::span(points.data() + at, end - at),
ozz::sample::kWhite, transform)) {
return false;
}

return true;
}

} // namespace sample
} // namespace ozz
31 changes: 27 additions & 4 deletions samples/framework/motion_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ bool LoadMotionTrack(const char* _filename, MotionTrack* _track);
// transform.
struct MotionAccumulator {
// Accumulates motion delta (new - last) and updates current transform.
void Update(const ozz::math::Transform& _new);

// Accumulates motion delta (new - last) and updates current transform.
// _delta_rotation is the rotation to pply to deform the path since last
// update. Hence, user is responsible for taking care of applying delta time
// if he wants to achieve a specific angular speed.
void Update(const ozz::math::Transform& _new,
const ozz::math::Quaternion& _rot);
const ozz::math::Quaternion& _delta_rotation);

// Tells the accumulator that the _new transform is the new origin.
// This is useful when animation loops, so next delta is computed from the new
Expand All @@ -74,22 +80,39 @@ struct MotionAccumulator {
// Character's current transform.
ozz::math::Transform current = ozz::math::Transform::identity();

ozz::math::Quaternion accum_rotation = ozz::math::Quaternion::identity();
// Accumulated rotation (since last teleport).
ozz::math::Quaternion rotation_accum_ = ozz::math::Quaternion::identity();
};

// Helper object samples a motion track to update a MotionAccumulator.
struct MotionSampler : public MotionAccumulator {
// Updates the accumulator with a new motion sample.
bool Update(const MotionTrack& _motion, float _ratio, int _loops);

// Updates the accumulator with a new motion sample.
// _delta_rotation is the rotation to pply to deform the path since last
// update. Hence, user is responsible for taking care of applying delta time
// if he wants to achieve a specific angular speed.
bool Update(const MotionTrack& _motion, float _ratio, int _loops,
const ozz::math::Quaternion& _angular_velocity);
const ozz::math::Quaternion& _delta_rotation);
};

// Samples a motion track at a given ratio.
bool SampleMotion(const MotionTrack& _tracks, float _ratio,
ozz::math::Transform* _transform);

// Draws a motion track around ratio _at, in range [_from, _to].
// _step is the delta ratio between each sample / point.
bool DrawMotion(ozz::sample::Renderer* _renderer,
const MotionTrack& _motion_track, float _from, float _at,
float _to, float _step, const ozz::math::Float4x4& _transform);

// See DrawMotion above. This version allows to apply a delta rotation to the
// path, where _delta_rotation is the rotation to apply each step.
bool DrawMotion(ozz::sample::Renderer* _renderer,
const MotionTrack& _motion_track, float _from, float _at,
float _to, float _step, const ozz::math::Float4x4& _transform,
const ozz::math::Quaternion& _rot);
const ozz::math::Quaternion& _delta_rotation);

} // namespace sample
} // namespace ozz
Expand Down

0 comments on commit b7e8747

Please sign in to comment.