载入中...
搜索中...
未找到
ControlAnim.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5#include <algorithm>
6
7namespace eve::animation {
8
9ControlAnim::ControlAnim(float frequencyHz, float dampingZeta, float response)
10 : frequencyHz_(frequencyHz), dampingZeta_(dampingZeta), response_(response) {
11 refreshCoeffs();
12}
13
14void ControlAnim::setFrequency(float frequencyHz) {
15 frequencyHz_ = frequencyHz;
16 refreshCoeffs();
17}
18
19void ControlAnim::setDamping(float dampingZeta) {
20 dampingZeta_ = dampingZeta;
21 refreshCoeffs();
22}
23
24void ControlAnim::setResponse(float response) {
25 response_ = response;
26 refreshCoeffs();
27}
28
29void ControlAnim::setIntegrator(const std::string &kind) {
30 if (kind == "secondOrder") {
31 integrator_ = Integrator::SecondOrder;
32 } else if (kind == "spring") {
33 integrator_ = Integrator::Spring;
34 } else if (kind == "pd") {
35 integrator_ = Integrator::Pd;
36 } else {
37 throw Exception("ControlAnim::setIntegrator: unknown kind '%s' (expected secondOrder|spring|pd)",
38 kind.c_str());
39 }
40}
41
42std::string ControlAnim::getIntegrator() const {
43 switch (integrator_) {
44 case Integrator::SecondOrder: return "secondOrder";
45 case Integrator::Spring: return "spring";
46 case Integrator::Pd: return "pd";
47 }
48 return "secondOrder";
49}
50
51void ControlAnim::refreshCoeffs() {
52 coeffs_ = makeSecondOrderCoeffs(frequencyHz_, dampingZeta_, response_);
53 pdGainsFromOmegaZeta(hzToOmega(frequencyHz_), dampingZeta_, kp_, kd_);
54}
55
56ControlAnim::Channel &ControlAnim::ensure(const std::string &name) {
57 auto it = channels_.find(name);
58 if (it != channels_.end()) return it->second;
59 Channel ch;
60 channels_.emplace(name, ch);
61 order_.push_back(name);
62 return channels_[name];
63}
64
65void ControlAnim::set(const std::string &name, float value) {
66 Channel &ch = ensure(name);
67 ch.y = value;
68 ch.yd = 0.f;
69 ch.x = value;
70 ch.xp = value;
71 ch.xdExplicit = 0.f;
72 ch.hasXd = false;
73 ch.hasPrevX = true;
74}
75
76void ControlAnim::setTarget(const std::string &name, float value) {
77 Channel &ch = ensure(name);
78 if (!ch.hasPrevX) {
79 ch.y = value;
80 ch.yd = 0.f;
81 ch.xp = value;
82 ch.hasPrevX = true;
83 }
84 ch.x = value;
85}
86
87void ControlAnim::setTargetVelocity(const std::string &name, float velocity) {
88 Channel &ch = ensure(name);
89 ch.xdExplicit = velocity;
90 ch.hasXd = true;
91}
92
93void ControlAnim::impulse(const std::string &name, float deltaVelocity) {
94 Channel &ch = ensure(name);
95 ch.yd += deltaVelocity;
96}
97
98bool ControlAnim::has(const std::string &name) const {
99 return channels_.find(name) != channels_.end();
100}
101
102float ControlAnim::get(const std::string &name) const {
103 auto it = channels_.find(name);
104 return it == channels_.end() ? 0.f : it->second.y;
105}
106
107float ControlAnim::getVelocity(const std::string &name) const {
108 auto it = channels_.find(name);
109 return it == channels_.end() ? 0.f : it->second.yd;
110}
111
112float ControlAnim::getTarget(const std::string &name) const {
113 auto it = channels_.find(name);
114 return it == channels_.end() ? 0.f : it->second.x;
115}
116
118 channels_.clear();
119 order_.clear();
120}
121
122void ControlAnim::remove(const std::string &name) {
123 channels_.erase(name);
124 order_.erase(std::remove(order_.begin(), order_.end(), name), order_.end());
125}
126
127std::string ControlAnim::getPropertyName(int index) const {
128 if (index < 0 || index >= static_cast<int>(order_.size())) return {};
129 return order_[static_cast<size_t>(index)];
130}
131
132void ControlAnim::update(float dt) {
133 if (dt <= 0.f) return;
134 const float omega = hzToOmega(frequencyHz_);
135
136 for (auto &kv : channels_) {
137 Channel &ch = kv.second;
138 float xd = 0.f;
139 if (ch.hasXd) {
140 xd = ch.xdExplicit;
141 } else if (ch.hasPrevX && dt > 1e-8f) {
142 xd = (ch.x - ch.xp) / dt;
143 }
144 ch.xp = ch.x;
145 ch.hasPrevX = true;
146
147 switch (integrator_) {
148 case Integrator::SecondOrder:
149 stepSecondOrder(dt, ch.x, xd, coeffs_, ch.y, ch.yd);
150 break;
151 case Integrator::Spring:
152 stepDampedSpring(dt, ch.x, omega, dampingZeta_, ch.y, ch.yd);
153 break;
154 case Integrator::Pd:
155 stepPd(dt, ch.x, xd, kp_, kd_, ch.y, ch.yd);
156 break;
157 }
158 }
159}
160
161} // namespace eve::animation
Tok kind
std::string value
const char * name
Definition RockMesh.cpp:21
float getVelocity(const std::string &name) const
void remove(const std::string &name)
ControlAnim(float frequencyHz=3.f, float dampingZeta=1.f, float response=1.f)
void set(const std::string &name, float value)
Create/update a channel: current value snaps to value, velocity cleared.
void setTarget(const std::string &name, float value)
Move the tracking target (does not snap state). Creates channel if missing.
float get(const std::string &name) const
void setDamping(float dampingZeta)
void setFrequency(float frequencyHz)
bool has(const std::string &name) const
float getTarget(const std::string &name) const
void setResponse(float response)
std::string getIntegrator() const
std::string getPropertyName(int index) const
void setIntegrator(const std::string &kind)
Integrator: "secondOrder" | "spring" | "pd". Invalid → exception.
void update(float dt)
Advance all channels by dt seconds.
void setTargetVelocity(const std::string &name, float velocity)
Optional explicit target velocity (used by secondOrder / pd).
void impulse(const std::string &name, float deltaVelocity)
Inject an instantaneous velocity impulse (procedural “hit”).
void stepPd(float dt, float target, float targetVel, float kp, float kd, float &y, float &yd)
Semi-implicit Euler PD step (unit mass): a = Kp (target − y) + Kd (targetVel − yd),...
void stepSecondOrder(float dt, float x, float xd, const SecondOrderCoeffs &c, float &y, float &yd)
Stable semi-implicit Euler step for a second-order tracker. Estimates input velocity from consecutive...
void pdGainsFromOmegaZeta(float omega, float zeta, float &kp, float &kd)
Unit-mass PD gains from natural frequency ω (rad/s) and damping ratio ζ.
SecondOrderCoeffs makeSecondOrderCoeffs(float frequencyHz, float dampingZeta, float response)
Build second-order coefficients from frequency (Hz), damping ζ, response r.
float hzToOmega(float frequencyHz)
ω (rad/s) from frequency in Hz.
void stepDampedSpring(float dt, float target, float angularFrequency, float dampingRatio, float &pos, float &vel)
Advance position/velocity relative to a set-point using closed-form spring step.