载入中...
搜索中...
未找到
MotionMatcherSelection.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <cmath>
3#include <limits>
7
8namespace eve::animation {
9eve::Result<int> MotionMatcher::setCandidateRanges(std::span<const MotionSearchRange> ranges) {
10 auto fail = [](const char* message) {
12 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, message, "candidateRanges", {}, "animation"));
13 };
14 if (!database_->isBaked() || ranges.empty() || ranges.size() > 100000)
15 return fail("candidate selection requires a baked database and bounded nonempty ranges");
16 std::vector<std::vector<MotionSearchRange>> perClip(database_->getClipCount());
17 std::size_t intervalCount = 0;
18 for (const auto& r : ranges) {
19 if (r.clipIndex < 0 || r.clipIndex >= database_->getClipCount() || !std::isfinite(r.start) ||
20 !std::isfinite(r.end) || !std::isfinite(r.costBias) || r.start < 0.f || r.end < r.start ||
21 r.end > database_->getClip(r.clipIndex)->getDuration() + 0.001f)
22 return fail("invalid candidate clip, time interval, or cost bias");
23 intervalCount += r.transitionBlocks.size() + r.costOverrides.size() + r.continuingCostOverrides.size();
24 if (intervalCount > 100000) return fail("too many candidate metadata intervals");
25 for (const auto& block : r.transitionBlocks)
26 if (!std::isfinite(block.start) || !std::isfinite(block.end) || block.start < 0.f ||
27 block.end <= block.start)
28 return fail("invalid transition block interval");
29 if (!std::isfinite(r.continuingCostBias)) return fail("invalid continuing cost bias");
30 for (const auto* overrides : {&r.costOverrides, &r.continuingCostOverrides})
31 for (const auto& cost : *overrides)
32 if (!std::isfinite(cost.start) || !std::isfinite(cost.end) || !std::isfinite(cost.costBias) ||
33 cost.start < 0.f || cost.end <= cost.start)
34 return fail("invalid cost override interval");
35 perClip[r.clipIndex].push_back(r);
36 }
37 const int count = database_->getFrameCount();
38 std::vector<int> selected;
39 std::vector<float> bias(count, 0.f);
40 std::vector<float> continuingBias(count, 0.f);
41 std::vector<unsigned char> mask(count, 0), noReselect(database_->getClipCount(), 0);
42 std::vector<unsigned char> blocked(count, 0);
43 for (int clipIndex = 0; clipIndex < database_->getClipCount(); ++clipIndex) {
44 const auto& clipRanges = perClip[clipIndex];
45 if (clipRanges.empty()) continue;
46 const int begin = database_->clipFrameOffsets_[static_cast<std::size_t>(clipIndex)];
47 const int end = database_->clipFrameOffsets_[static_cast<std::size_t>(clipIndex + 1)];
48 for (int i = begin; i < end; ++i) {
49 const auto& frame = database_->frameAt(i);
50 float best = std::numeric_limits<float>::infinity();
51 for (const auto& r : clipRanges) {
52 for (const auto& block : r.transitionBlocks)
53 if (frame.time >= block.start && frame.time < block.end) blocked[i] = 1;
54 if (frame.time + 1e-5f < r.start || frame.time - 1e-5f > r.end) continue;
55 float rangeBias = r.costBias;
56 for (const auto& cost : r.costOverrides)
57 if (frame.time >= cost.start && frame.time < cost.end) rangeBias = cost.costBias;
58 float rangeContinuingBias = r.continuingCostBias;
59 for (const auto& cost : r.continuingCostOverrides)
60 if (frame.time >= cost.start && frame.time < cost.end) rangeContinuingBias = cost.costBias;
61 if (rangeBias < best) {
62 best = rangeBias;
63 continuingBias[i] = rangeContinuingBias;
64 }
65 if (r.disableReselection) noReselect[frame.clipIndex] = 1;
66 }
67 if (!std::isfinite(best)) continue;
68 selected.push_back(i);
69 mask[i] = 1;
70 bias[i] = best;
71 }
72 }
73 if (selected.empty()) return fail("candidate selection contains no sampled frames");
74 candidateFrames_.swap(selected);
75 candidateBias_.swap(bias);
76 candidateContinuingBias_.swap(continuingBias);
77 candidateMask_.swap(mask);
78 transitionBlocked_.swap(blocked);
79 disableReselection_.swap(noReselect);
80 filtered_ = true;
81 return eve::Result<int>::success(static_cast<int>(candidateFrames_.size()),
83}
84
86 if (database_->hasLocomotionFeatures() || database_->hasFeatureLayout() || pose.getBoneCount() != pose_.getBoneCount())
88 "basic query pose requires the basic layout and matching bone count",
89 "queryPose", {}, "animation"));
90 queryPose_.copyFrom(&pose);
91 hasQueryPose_ = true;
93}
94
95eve::Result<void> MotionMatcher::setTrajectory(std::span<const MotionTrajectorySample> samples) {
96 if (database_->hasLocomotionFeatures() || database_->hasFeatureLayout() || samples.size() != 3 || std::any_of(samples.begin(), samples.end(), [](const auto& s) {
97 return !std::isfinite(s.x) || !std::isfinite(s.z) || !std::isfinite(s.yaw);
98 }))
100 "trajectory requires three finite samples",
101 "trajectory", {}, "animation"));
102 std::copy(samples.begin(), samples.end(), trajectory_.begin());
103 hasTrajectory_ = true;
105}
106} // namespace eve::animation
eve::EntitySpatialPose pose
const std::string & s
int mask
eve::resource::CostSpec cost
std::string message
double r
float begin
float bias
std::uint32_t count
std::map< Cell, int > best
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
float getDuration() const
Returns the duration.
Definition AnimClip.h:163
Evaluated local (and optional world) pose for an AnimSkeleton. Script type: AnimPose.
Definition AnimPose.h:17
int getBoneCount() const
Returns the bone count.
Definition AnimPose.h:36
void copyFrom(const AnimPose *other)
Copies from.
Definition AnimPose.cpp:91
bool hasFeatureLayout() const
Whether this database uses an explicitly configured variable layout.
bool isBaked() const
True when baked.
AnimClip * getClip(int clipIndex) const
Returns the clip.
const Frame & frameAt(int index) const
bool hasLocomotionFeatures() const
Whether this database uses the 30-dimensional locomotion layout.
int getFrameCount() const
Returns the frame count.
int getClipCount() const
Returns the clip count.
eve::Result< void > setQueryPose(const AnimPose &pose)
Copy the character's current local pose for the next search, including action handoffs.
eve::Result< int > setCandidateRanges(std::span< const MotionSearchRange > ranges)
Atomically replace searchable intervals, retaining original database frame IDs.
eve::Result< void > setTrajectory(std::span< const MotionTrajectorySample > samples)
Set predictions at 0.33, 0.66, and 1.0 seconds instead of constant-velocity prediction.