载入中...
搜索中...
未找到
AnimInertializer.cpp
浏览该文件的文档.
2#include <cmath>
4
5namespace eve::animation {
11namespace {
12bool finitePose(const AnimPose& pose, int count) {
13 if (count <= 0 || pose.getBoneCount() != count) return false;
14 for (int i = 0; i < count; ++i) {
15 const auto& t = pose.local(i);
16 for (float v : {t.px, t.py, t.pz, t.qx, t.qy, t.qz, t.qw, t.sx, t.sy, t.sz})
17 if (!std::isfinite(v)) return false;
18 const double norm = double(t.qx) * t.qx + double(t.qy) * t.qy + double(t.qz) * t.qz + double(t.qw) * t.qw;
19 if (norm < 1e-12 || norm > 1e12) return false;
20 }
21 return true;
22}
23} // namespace
24AnimInertializer::AnimInertializer() : impl_(std::make_unique<Impl>()) {}
26
28 const AnimPose& target, const AnimPose& previousTarget, float historySeconds,
29 float durationSeconds, std::span<const float> boneTimeFactors) {
30 const int count = source.getBoneCount();
31 if (!std::isfinite(historySeconds) || historySeconds <= 0.f || historySeconds > 1.f ||
32 !std::isfinite(durationSeconds) || durationSeconds < 0.f || durationSeconds > 10.f ||
33 !finitePose(source, count) || !finitePose(previousSource, count) || !finitePose(target, count) ||
34 !finitePose(previousTarget, count))
36 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "transition requires matching finite poses and valid history/duration", "poseTransition", {}, "animation"));
37 if (!boneTimeFactors.empty() && boneTimeFactors.size() != static_cast<std::size_t>(count))
39 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "time factors must be empty or match the bone count", "poseTransition", {}, "animation"));
40 for (float factor : boneTimeFactors)
41 if (!std::isfinite(factor) || factor < 0.f || factor > 1.f)
43 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "bone time factors must be finite and between zero and one", "poseTransition", {}, "animation"));
44 auto next = std::make_unique<Impl>();
45 next->factors.assign(boneTimeFactors.begin(), boneTimeFactors.end());
46 next->inertia.remember(previousSource, historySeconds);
47 next->inertia.begin(source, target, previousTarget, durationSeconds);
48 for (const auto& values : next->inertia.velocities)
49 for (float v : values)
50 if (!std::isfinite(v)) return eve::Result<void>::failure(
51 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "transition history overflows velocity range", "poseTransition", {}, "animation"));
52 next->inertia.apply(target, 0.f, next->output, next->factors);
53 if (!finitePose(next->output, count)) return eve::Result<void>::failure(
54 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "transition output is not finite", "poseTransition", {}, "animation"));
55 impl_.swap(next);
57}
58
60 if (!std::isfinite(elapsedSeconds) || elapsedSeconds < 0.f || !finitePose(target, impl_->output.getBoneCount()))
62 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "evaluation requires an initialized transition, matching finite target and elapsed time", "poseTransition", {}, "animation"));
63 AnimPose next;
64 impl_->inertia.apply(target, elapsedSeconds, next, impl_->factors);
65 if (!finitePose(next, target.getBoneCount())) return eve::Result<void>::failure(
66 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "transition output is not finite", "poseTransition", {}, "animation"));
67 impl_->output = std::move(next);
69}
70const AnimPose& AnimInertializer::pose() const noexcept { return impl_->output; }
71} // namespace eve::animation
LogicalId target
eve::EntitySpatialPose pose
std::map< std::string, Var > values
float v
float t
std::uint32_t count
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
AnimInertializer()
Construct an empty, independently owned transition.
const AnimPose & pose() const noexcept
Borrow read-only output, valid until destruction; contents change after successful begin/evaluate....
eve::Result< void > begin(const AnimPose &source, const AnimPose &previousSource, const AnimPose &target, const AnimPose &previousTarget, float historySeconds, float durationSeconds, std::span< const float > boneTimeFactors={})
Atomically begin or interrupt a transition using actual outgoing pose history.
~AnimInertializer()
Release owned samples; no external objects are accessed.
eve::Result< void > evaluate(const AnimPose &target, float elapsedSeconds)
Evaluate the moving target at an absolute elapsed simulation time since begin.
Evaluated local (and optional world) pose for an AnimSkeleton. Script type: AnimPose.
Definition AnimPose.h:17