12 void addInterpolatedKeysRecursive(
GraphNode* node,
13 std::vector<InterpolatedKey>& interpolatedKeys,
14 std::unordered_map<std::string, size_t>& interpolatedKeyDict,
15 std::unordered_map<std::string, int>& currKeyIndices)
22 interpKey.
name = node->name();
23 interpolatedKeyDict[interpKey.name] = interpolatedKeys.size();
24 currKeyIndices[interpKey.name] = 0;
25 interpolatedKeys.push_back(interpKey);
27 for (
auto* child : node->children()) {
28 addInterpolatedKeysRecursive(child, interpolatedKeys, interpolatedKeyDict, currKeyIndices);
35 addInterpolatedKeysRecursive(graph, _interpolatedKeys, _interpolatedKeyDict, _currKeyIndices);
48 for (
const auto& key : _interpolatedKeys) {
49 _currKeyIndices[key.name] = 0;
58 return a + (b - a) * alpha;
61 Quaternion Skeleton::slerpQuat(
const Quaternion& a,
const Quaternion& b,
const float alpha)
73 float dot = ax * bx + ay * by + az * bz + aw * bw;
83 constexpr float epsilon = 1e-6f;
84 float scale0 = 1.0f - alpha;
87 if ((1.0f - dot) > epsilon) {
88 const float theta = std::acos(std::clamp(dot, -1.0f, 1.0f));
89 const float invSinTheta = 1.0f / std::sin(theta);
90 scale0 = std::sin((1.0f - alpha) * theta) * invSinTheta;
91 scale1 = std::sin(alpha * theta) * invSinTheta;
95 scale0 * ax + scale1 * bx,
96 scale0 * ay + scale1 * by,
97 scale0 * az + scale1 * bz,
98 scale0 * aw + scale1 * bw);
100 return result.normalized();
109 const auto& nodes = _animation->nodes();
110 const float duration = _animation->duration();
112 if ((_time == duration) && !_looping) {
118 if (_time > duration) {
119 _time = _looping ? 0.0f : duration;
120 for (
const auto& node : nodes) {
121 _currKeyIndices[node.name()] = 0;
123 }
else if (_time < 0.0f) {
124 _time = _looping ? duration : 0.0f;
125 for (
const auto& node : nodes) {
126 _currKeyIndices[node.name()] =
static_cast<int>(node.keys().size()) - 2;
130 const int offset = (delta >= 0.0f ? 1 : -1);
132 for (
const auto& node : nodes) {
133 const std::string& nodeName = node.name();
134 const auto interpIt = _interpolatedKeyDict.find(nodeName);
135 if (interpIt == _interpolatedKeyDict.end()) {
140 const auto& keys = node.keys();
145 bool foundKey =
false;
146 if (keys.size() != 1) {
147 int currKeyIndex = _currKeyIndices[nodeName];
148 for (; currKeyIndex < static_cast<int>(keys.size()) - 1 && currKeyIndex >= 0; currKeyIndex += offset) {
149 const auto& k1 = keys[currKeyIndex];
150 const auto& k2 = keys[currKeyIndex + 1];
152 if ((k1.time <= _time) && (k2.time >= _time)) {
153 const float alpha = (k2.time > k1.time) ? ((_time - k1.time) / (k2.time - k1.time)) : 0.0f;
155 interpKey.
pos = lerpVec3(k1.position, k2.position, alpha);
156 interpKey.
quat = slerpQuat(k1.rotation, k2.rotation, alpha);
157 interpKey.
scale = lerpVec3(k1.scale, k2.scale, alpha);
160 _currKeyIndices[nodeName] = currKeyIndex;
167 if (keys.size() == 1 || (!foundKey && _time == 0.0f && _looping)) {
168 interpKey.
pos = keys[0].position;
169 interpKey.
quat = keys[0].rotation;
170 interpKey.
scale = keys[0].scale;
178 if (!skel1 || !skel2) {
182 const size_t numNodes = std::min(_interpolatedKeys.size(), std::min(skel1->_interpolatedKeys.size(), skel2->_interpolatedKeys.size()));
183 for (
size_t i = 0; i <
numNodes; i++) {
184 const auto& key1 = skel1->_interpolatedKeys[i];
185 const auto& key2 = skel2->_interpolatedKeys[i];
186 auto& dstKey = _interpolatedKeys[i];
188 if (key1.written && key2.written) {
189 dstKey.quat = slerpQuat(key1.quat, key2.quat, alpha);
190 dstKey.pos = lerpVec3(key1.pos, key2.pos, alpha);
191 dstKey.scale = lerpVec3(key1.scale, key2.scale, alpha);
192 dstKey.written =
true;
193 }
else if (key1.written) {
194 dstKey.quat = key1.quat;
195 dstKey.pos = key1.pos;
196 dstKey.scale = key1.scale;
197 dstKey.written =
true;
198 }
else if (key2.written) {
199 dstKey.quat = key2.quat;
200 dstKey.pos = key2.pos;
201 dstKey.scale = key2.scale;
202 dstKey.written =
true;
212 for (
auto& interpKey : _interpolatedKeys) {
213 interpKey.setTarget(_graph->findByName(interpKey.name));
216 for (
auto& interpKey : _interpolatedKeys) {
217 interpKey.setTarget(
nullptr);
228 for (
auto& interpKey : _interpolatedKeys) {
229 if (!interpKey.written) {
233 GraphNode* transform = interpKey.getTarget();
242 interpKey.written =
false;
Hierarchical scene graph node with local/world transforms and parent-child relationships.
void setLocalPosition(float x, float y, float z)
void setLocalRotation(const Quaternion &rotation)
void setLocalScale(float x, float y, float z)
void blend(const Skeleton *skel1, const Skeleton *skel2, float alpha)
void setGraph(GraphNode *graph)
Skeleton(GraphNode *graph)
void addTime(float delta)
void setAnimation(Animation *value)
void setCurrentTime(float value)
3D vector for positions, directions, and normals with multi-backend SIMD acceleration.