载入中...
搜索中...
未找到
AnimControlMath.h
浏览该文件的文档.
1#pragma once
2
3#include <cmath>
4#include <algorithm>
5
6namespace eve::animation {
7
21 float k1 = 0.f;
22 float k2 = 1.f;
23 float k3 = 0.f;
24};
25
27inline SecondOrderCoeffs makeSecondOrderCoeffs(float frequencyHz, float dampingZeta,
28 float response) {
29 const float f = std::max(frequencyHz, 1e-4f);
30 const float z = std::max(dampingZeta, 0.f);
31 const float twoPiF = 6.283185307179586f * f;
33 c.k1 = z / (3.141592653589793f * f);
34 c.k2 = 1.f / (twoPiF * twoPiF);
35 c.k3 = response * z / twoPiF;
36 return c;
37}
38
44inline void stepSecondOrder(float dt, float x, float xd, const SecondOrderCoeffs &c, float &y,
45 float &yd) {
46 if (dt <= 0.f) return;
47 const float k2Stable = std::max(c.k2, std::max(dt * dt * 0.5f + dt * c.k1 * 0.5f, dt * c.k1));
48 y += dt * yd;
49 yd += dt * (x + c.k3 * xd - y - c.k1 * yd) / k2Stable;
50}
51
54 float posPos = 1.f;
55 float posVel = 0.f;
56 float velPos = 0.f;
57 float velVel = 1.f;
58};
59
60inline DampedSpringStep makeDampedSpringStep(float dt, float angularFrequency, float dampingRatio) {
62 if (dt <= 0.f || angularFrequency <= 0.f) return s;
63
64 const float eps = 1e-4f;
65 const float omega = angularFrequency;
66 const float zeta = std::max(dampingRatio, 0.f);
67
68 if (zeta > 1.f + eps) {
69 // Over-damped
70 const float za = -omega * zeta;
71 const float zb = omega * std::sqrt(zeta * zeta - 1.f);
72 const float z1 = za - zb;
73 const float z2 = za + zb;
74 const float e1 = std::exp(z1 * dt);
75 const float e2 = std::exp(z2 * dt);
76 const float invTwoZb = 1.f / (2.f * zb);
77 const float e1Over = e1 * invTwoZb;
78 const float e2Over = e2 * invTwoZb;
79 const float z1e1 = z1 * e1Over;
80 const float z2e2 = z2 * e2Over;
81 s.posPos = e1Over * z2 - z2e2 + e2;
82 s.posVel = -e1Over + e2Over;
83 s.velPos = (z1e1 - z2e2 + e2) * z2;
84 s.velVel = -z1e1 + z2e2;
85 } else if (zeta < 1.f - eps) {
86 // Under-damped
87 const float omegaZeta = omega * zeta;
88 const float alpha = omega * std::sqrt(1.f - zeta * zeta);
89 const float expTerm = std::exp(-omegaZeta * dt);
90 const float cosTerm = std::cos(alpha * dt);
91 const float sinTerm = std::sin(alpha * dt);
92 const float invAlpha = 1.f / alpha;
93 const float expSin = expTerm * sinTerm;
94 const float expCos = expTerm * cosTerm;
95 const float expOzSin = expTerm * omegaZeta * sinTerm * invAlpha;
96 s.posPos = expCos + expOzSin;
97 s.posVel = expSin * invAlpha;
98 s.velPos = -expSin * alpha - omegaZeta * expOzSin;
99 s.velVel = expCos - expOzSin;
100 } else {
101 // Critically damped
102 const float expTerm = std::exp(-omega * dt);
103 const float timeExp = dt * expTerm;
104 const float timeExpFreq = timeExp * omega;
105 s.posPos = timeExpFreq + expTerm;
106 s.posVel = timeExp;
107 s.velPos = -omega * timeExpFreq;
108 s.velVel = -timeExpFreq + expTerm;
109 }
110 return s;
111}
112
114inline void stepDampedSpring(float dt, float target, float angularFrequency, float dampingRatio,
115 float &pos, float &vel) {
116 const DampedSpringStep s = makeDampedSpringStep(dt, angularFrequency, dampingRatio);
117 const float oldPos = pos - target;
118 const float oldVel = vel;
119 const float newPos = oldPos * s.posPos + oldVel * s.posVel;
120 const float newVel = oldPos * s.velPos + oldVel * s.velVel;
121 pos = newPos + target;
122 vel = newVel;
123}
124
126inline void pdGainsFromOmegaZeta(float omega, float zeta, float &kp, float &kd) {
127 const float w = std::max(omega, 0.f);
128 const float z = std::max(zeta, 0.f);
129 kp = w * w;
130 kd = 2.f * z * w;
131}
132
137inline void stepPd(float dt, float target, float targetVel, float kp, float kd, float &y,
138 float &yd) {
139 if (dt <= 0.f) return;
140 const float a = kp * (target - y) + kd * (targetVel - yd);
141 yd += a * dt;
142 y += yd * dt;
143}
144
146inline float hzToOmega(float frequencyHz) {
147 return 6.283185307179586f * std::max(frequencyHz, 0.f);
148}
149
150} // namespace eve::animation
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
int w
uint32_t a
uint32_t c
float f
uint32_t s
Definition Weather.cpp:28
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...
DampedSpringStep makeDampedSpringStep(float dt, float angularFrequency, float dampingRatio)
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.
Closed-form coefficients for one damped-spring time step (Juckett).
Control-theory helpers for procedural animation.