diff --git a/samples/framework/motion_utils.cc b/samples/framework/motion_utils.cc index 6bd1cd88e..1da9a383b 100644 --- a/samples/framework/motion_utils.cc +++ b/samples/framework/motion_utils.cc @@ -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; @@ -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) { @@ -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)) { @@ -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. @@ -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, @@ -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 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 diff --git a/samples/framework/motion_utils.h b/samples/framework/motion_utils.h index aa8f92d47..fe1e4ac87 100644 --- a/samples/framework/motion_utils.h +++ b/samples/framework/motion_utils.h @@ -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 @@ -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