VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
animEvaluator.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3#include "animEvaluator.h"
4
5#include <algorithm>
6#include <cmath>
7#include <set>
8
9#include "scene/graphNode.h"
10
11namespace visutwin::canvas
12{
13 AnimEvaluator::AnimEvaluator(std::unique_ptr<AnimBinder> binder) : _binder(std::move(binder))
14 {
15 }
16
17 void AnimEvaluator::addClip(const std::shared_ptr<AnimClip>& clip)
18 {
19 if (!clip) {
20 return;
21 }
22 _clips.push_back(clip);
23 }
24
25 void AnimEvaluator::removeClip(const size_t index)
26 {
27 if (index >= _clips.size()) {
28 return;
29 }
30 _clips.erase(_clips.begin() + static_cast<std::ptrdiff_t>(index));
31 }
32
34 {
35 _clips.clear();
36 }
37
38 Vector3 AnimEvaluator::lerpVec3(const Vector3& a, const Vector3& b, const float alpha)
39 {
40 return a + (b - a) * alpha;
41 }
42
43 Quaternion AnimEvaluator::slerpQuat(const Quaternion& a, const Quaternion& b, const float alpha)
44 {
45 float ax = a.getX();
46 float ay = a.getY();
47 float az = a.getZ();
48 float aw = a.getW();
49
50 float bx = b.getX();
51 float by = b.getY();
52 float bz = b.getZ();
53 float bw = b.getW();
54
55 float dot = ax * bx + ay * by + az * bz + aw * bw;
56 if (dot < 0.0f) {
57 bx = -bx;
58 by = -by;
59 bz = -bz;
60 bw = -bw;
61 dot = -dot;
62 }
63
64 constexpr float epsilon = 1e-6f;
65 float scale0 = 1.0f - alpha;
66 float scale1 = alpha;
67
68 if ((1.0f - dot) > epsilon) {
69 const float theta = std::acos(std::clamp(dot, -1.0f, 1.0f));
70 const float invSinTheta = 1.0f / std::sin(theta);
71 scale0 = std::sin((1.0f - alpha) * theta) * invSinTheta;
72 scale1 = std::sin(alpha * theta) * invSinTheta;
73 }
74
75 return Quaternion(
76 scale0 * ax + scale1 * bx,
77 scale0 * ay + scale1 * by,
78 scale0 * az + scale1 * bz,
79 scale0 * aw + scale1 * bw).normalized();
80 }
81
82 void AnimEvaluator::update(const float dt)
83 {
84 if (!_binder || _clips.empty()) {
85 return;
86 }
87
88 for (const auto& clip : _clips) {
89 if (clip) {
90 clip->update(dt);
91 }
92 }
93
94 _tmpA.clear();
95 _tmpB.clear();
96
97 if (_clips[0]) {
98 _clips[0]->eval(_tmpA);
99 }
100
101 float blendWeight = 1.0f;
102 if (_clips.size() > 1 && _clips[1]) {
103 _clips[1]->eval(_tmpB);
104 blendWeight = std::clamp(_clips[1]->blendWeight(), 0.0f, 1.0f);
105 }
106
107 std::set<std::string> allNodes;
108 for (const auto& [name, _] : _tmpA) {
109 (void)_;
110 allNodes.insert(name);
111 }
112 for (const auto& [name, _] : _tmpB) {
113 (void)_;
114 allNodes.insert(name);
115 }
116
117 for (const auto& nodeName : allNodes) {
118 GraphNode* node = _binder->resolve(nodeName);
119 if (!node) {
120 continue;
121 }
122
123 const auto aIt = _tmpA.find(nodeName);
124 const auto bIt = _tmpB.find(nodeName);
125
126 if (bIt == _tmpB.end()) {
127 const auto& a = aIt->second;
128 if (a.hasPosition) {
129 node->setLocalPosition(a.position);
130 }
131 if (a.hasRotation) {
132 node->setLocalRotation(a.rotation);
133 }
134 if (a.hasScale) {
135 node->setLocalScale(a.scale);
136 }
137 continue;
138 }
139
140 if (aIt == _tmpA.end()) {
141 const auto& b = bIt->second;
142 if (b.hasPosition) {
143 node->setLocalPosition(b.position);
144 }
145 if (b.hasRotation) {
146 node->setLocalRotation(b.rotation);
147 }
148 if (b.hasScale) {
149 node->setLocalScale(b.scale);
150 }
151 continue;
152 }
153
154 const auto& a = aIt->second;
155 const auto& b = bIt->second;
156
157 if (a.hasPosition || b.hasPosition) {
158 node->setLocalPosition(lerpVec3(a.position, b.position, blendWeight));
159 }
160 if (a.hasRotation || b.hasRotation) {
161 node->setLocalRotation(slerpQuat(a.rotation, b.rotation, blendWeight));
162 }
163 if (a.hasScale || b.hasScale) {
164 node->setLocalScale(lerpVec3(a.scale, b.scale, blendWeight));
165 }
166 }
167 }
168}
AnimEvaluator(std::unique_ptr< AnimBinder > binder)
void addClip(const std::shared_ptr< AnimClip > &clip)
Hierarchical scene graph node with local/world transforms and parent-child relationships.
Definition graphNode.h:28
void setLocalPosition(float x, float y, float z)
std::vector< GraphNode * > find(const std::function< bool(GraphNode *)> &predicate)
Find all descendants (and self) matching a predicate.
void setLocalRotation(const Quaternion &rotation)
Definition graphNode.cpp:77
void setLocalScale(float x, float y, float z)
3D vector for positions, directions, and normals with multi-backend SIMD acceleration.
Definition vector3.h:29