载入中...
搜索中...
未找到
MotionTypes.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
4#include "common/Exception.h"
5
6#include <algorithm>
7#include <cmath>
8#include <cstdint>
9#include <cstring>
10
11#ifndef M_PI
12#define M_PI 3.14159265358979323846
13#endif
14
15namespace eve::animation {
16
17namespace {
18
19float clamp01(float t) { return std::clamp(t, 0.f, 1.f); }
20
21} // namespace
22
31
40
41
51
53 if (!x_ || !y_ || !z_) {
55 eve::DiagnosticCode::PreconditionViolation, "Vec3PointerSink.write: target is null"));
56 }
57 *x_ = value.x;
58 *y_ = value.y;
59 *z_ = value.z;
61}
62
63float evaluateMotionEase(float t, const char *kind) {
64 t = clamp01(t);
65 if (!kind || kind[0] == '\0' || std::strcmp(kind, "linear") == 0) return t;
66 if (std::strcmp(kind, "inQuad") == 0) return t * t;
67 if (std::strcmp(kind, "outQuad") == 0) return 1.f - (1.f - t) * (1.f - t);
68 if (std::strcmp(kind, "inOutQuad") == 0)
69 return t < 0.5f ? 2.f * t * t : 1.f - std::pow(-2.f * t + 2.f, 2.f) * 0.5f;
70 if (std::strcmp(kind, "inCubic") == 0) return t * t * t;
71 if (std::strcmp(kind, "outCubic") == 0) return 1.f - std::pow(1.f - t, 3.f);
72 if (std::strcmp(kind, "inOutCubic") == 0)
73 return t < 0.5f ? 4.f * t * t * t : 1.f - std::pow(-2.f * t + 2.f, 3.f) * 0.5f;
74 if (std::strcmp(kind, "inSine") == 0) return 1.f - std::cos(t * float(M_PI) * 0.5f);
75 if (std::strcmp(kind, "outSine") == 0) return std::sin(t * float(M_PI) * 0.5f);
76 if (std::strcmp(kind, "inOutSine") == 0) return -(std::cos(float(M_PI) * t) - 1.f) * 0.5f;
77 if (std::strcmp(kind, "inExpo") == 0) return t <= 0.f ? 0.f : std::pow(2.f, 10.f * t - 10.f);
78 if (std::strcmp(kind, "outExpo") == 0) return t >= 1.f ? 1.f : 1.f - std::pow(2.f, -10.f * t);
79 if (std::strcmp(kind, "inOutExpo") == 0) {
80 if (t <= 0.f) return 0.f;
81 if (t >= 1.f) return 1.f;
82 return t < 0.5f ? std::pow(2.f, 20.f * t - 10.f) * 0.5f
83 : (2.f - std::pow(2.f, -20.f * t + 10.f)) * 0.5f;
84 }
85
86 // Back (overshoot)
87 constexpr float backS = 1.70158f;
88 if (std::strcmp(kind, "inBack") == 0) return t * t * ((backS + 1.f) * t - backS);
89 if (std::strcmp(kind, "outBack") == 0) {
90 const float u = t - 1.f;
91 return u * u * ((backS + 1.f) * u + backS) + 1.f;
92 }
93 if (std::strcmp(kind, "inOutBack") == 0) {
94 const float s = backS * 1.525f;
95 if (t < 0.5f) {
96 const float u = t * 2.f;
97 return 0.5f * (u * u * ((s + 1.f) * u - s));
98 }
99 const float u = t * 2.f - 2.f;
100 return 0.5f * (u * u * ((s + 1.f) * u + s) + 2.f);
101 }
102
103 // Elastic
104 if (std::strcmp(kind, "inElastic") == 0) {
105 if (t <= 0.f || t >= 1.f) return t;
106 return -std::pow(2.f, 10.f * t - 10.f) *
107 std::sin((t * 10.f - 10.75f) * (2.f * float(M_PI) / 3.f));
108 }
109 if (std::strcmp(kind, "outElastic") == 0) {
110 if (t <= 0.f || t >= 1.f) return t;
111 return std::pow(2.f, -10.f * t) *
112 std::sin((t * 10.f - 0.75f) * (2.f * float(M_PI) / 3.f)) +
113 1.f;
114 }
115 if (std::strcmp(kind, "inOutElastic") == 0) {
116 if (t <= 0.f || t >= 1.f) return t;
117 if (t < 0.5f) {
118 return -0.5f * std::pow(2.f, 20.f * t - 10.f) *
119 std::sin((20.f * t - 11.125f) * (2.f * float(M_PI) / 4.5f));
120 }
121 return std::pow(2.f, -20.f * t + 10.f) *
122 std::sin((20.f * t - 11.125f) * (2.f * float(M_PI) / 4.5f)) * 0.5f +
123 1.f;
124 }
125
126 // Bounce
127 auto outBounce = [](float x) {
128 constexpr float n1 = 7.5625f;
129 constexpr float d1 = 2.75f;
130 if (x < 1.f / d1) return n1 * x * x;
131 if (x < 2.f / d1) {
132 x -= 1.5f / d1;
133 return n1 * x * x + 0.75f;
134 }
135 if (x < 2.5f / d1) {
136 x -= 2.25f / d1;
137 return n1 * x * x + 0.9375f;
138 }
139 x -= 2.625f / d1;
140 return n1 * x * x + 0.984375f;
141 };
142 if (std::strcmp(kind, "inBounce") == 0) return 1.f - outBounce(1.f - t);
143 if (std::strcmp(kind, "outBounce") == 0) return outBounce(t);
144 if (std::strcmp(kind, "inOutBounce") == 0) {
145 return t < 0.5f ? (1.f - outBounce(1.f - 2.f * t)) * 0.5f
146 : (1.f + outBounce(2.f * t - 1.f)) * 0.5f;
147 }
148
149 throw Exception("Motion.ease: unknown kind '%s'", kind);
150}
151
152
154 if (!r_ || !g_ || !b_ || !a_) {
156 eve::DiagnosticCode::PreconditionViolation, "ColorPointerSink.write: target is null"));
157 }
158 *r_ = value.r;
159 *g_ = value.g;
160 *b_ = value.b;
161 *a_ = value.a;
163}
164
166 if (!x_ || !y_ || !z_ || !w_) {
168 eve::DiagnosticCode::PreconditionViolation, "QuatPointerSink.write: target is null"));
169 }
170 *x_ = value.x;
171 *y_ = value.y;
172 *z_ = value.z;
173 *w_ = value.w;
175}
176
177float evaluateMotionOscillation(float t, int frequency, float dampingRatio) {
178 if (!(t > 0.f) || !(t < 1.f) || frequency < 1) return 0.f;
179 if (!std::isfinite(t) || !std::isfinite(dampingRatio)) return 0.f;
180 const float freq = static_cast<float>(frequency);
181 const float angular = freq * float(M_PI);
182 const float dampingFactor = dampingRatio * freq / (2.f * float(M_PI));
183 return std::sin(angular * t) * std::exp(-dampingFactor * t);
184}
185
186float evaluateMotionShakeSign(std::uint32_t seed, int frequency, float t, int axis) {
187 if (frequency < 1) frequency = 1;
188 const float clamped = std::clamp(t, 0.f, 1.f);
189 const int step = static_cast<int>(clamped * static_cast<float>(frequency) * 2.f);
190 std::uint32_t h = seed;
191 h ^= 0x9E3779B9u * (static_cast<std::uint32_t>(axis) + 1u);
192 h ^= 0x85EBCA6Bu * (static_cast<std::uint32_t>(step) + 1u);
193 h ^= static_cast<std::uint32_t>(frequency) * 0xC2B2AE35u;
194 h ^= h >> 16;
195 h *= 0x7FEB352Du;
196 h ^= h >> 15;
197 h *= 0x846CA68Bu;
198 h ^= h >> 16;
199 // Map to [-1, 1]
200 const float u = static_cast<float>(h & 0x00FFFFFFu) / static_cast<float>(0x00FFFFFFu);
201 return u * 2.f - 1.f;
202}
203
205 return MotionColor{a.r + (b.r - a.r) * t, a.g + (b.g - a.g) * t, a.b + (b.b - a.b) * t,
206 a.a + (b.a - a.a) * t};
207}
208
210 auto normalize = [](MotionQuat q) {
211 const float len = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
212 if (!(len > 0.f)) return MotionQuat{0.f, 0.f, 0.f, 1.f};
213 const float inv = 1.f / len;
214 return MotionQuat{q.x * inv, q.y * inv, q.z * inv, q.w * inv};
215 };
216 a = normalize(a);
217 b = normalize(b);
218 float dot = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
219 if (dot < 0.f) {
220 b = MotionQuat{-b.x, -b.y, -b.z, -b.w};
221 dot = -dot;
222 }
223 constexpr float kEps = 0.9995f;
224 if (dot > kEps) {
225 return normalize(MotionQuat{a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t,
226 a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t});
227 }
228 const float theta0 = std::acos(std::clamp(dot, -1.f, 1.f));
229 const float theta = theta0 * t;
230 const float sinTheta0 = std::sin(theta0);
231 const float s0 = std::sin(theta0 - theta) / sinTheta0;
232 const float s1 = std::sin(theta) / sinTheta0;
233 return MotionQuat{a.x * s0 + b.x * s1, a.y * s0 + b.y * s1, a.z * s0 + b.z * s1,
234 a.w * s0 + b.w * s1};
235}
236
237} // namespace eve::animation
double value
float x
Definition AnimClip.cpp:738
const std::string & s
Stable, structured diagnostics shared by engine modules.
float u
Definition Grass.cpp:233
std::array< double, 10 > q
int h
TokenKind kind
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
#define M_PI
LitMotion-style typed motion handles, values, and sink interfaces.
std::uint32_t seed
Definition PointSet.cpp:807
float t
float step
Definition TreeMesh.cpp:314
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
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
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
eve::Result< void > write(MotionColor value) override
Writes .
eve::Result< void > write(float value) override
Writes .
eve::Result< void > write(float value) override
Writes .
eve::Result< void > write(MotionQuat value) override
Writes .
eve::Result< void > write(MotionVec2 value) override
Writes .
eve::Result< void > write(MotionVec3 value) override
Writes .
MotionQuat slerpMotionQuat(MotionQuat a, MotionQuat b, float t)
Spherical linear interpolation for MotionQuat (shortest path).
float evaluateMotionOscillation(float t, int frequency, float dampingRatio)
LitMotion-style damped sine envelope in [0,1] progress.
MotionColor lerpMotionColor(MotionColor a, MotionColor b, float t)
Component-wise lerp for MotionColor.
float evaluateMotionShakeSign(std::uint32_t seed, int frequency, float t, int axis)
Deterministic shake sign in [-1,1] for axis (0..n).
float evaluateMotionEase(float t, const char *kind)
Evaluate an ease curve; kinds match Math.ease / Tween.
Compact RGBA color used by motion adapters.
Definition MotionTypes.h:52
Compact quaternion used by motion adapters (xyzw).
Definition MotionTypes.h:60
Compact float2 used by motion adapters (avoids graphics math deps).
Definition MotionTypes.h:39
Compact float3 used by motion adapters.
Definition MotionTypes.h:45