-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnimation.cpp
More file actions
125 lines (109 loc) · 4.28 KB
/
Animation.cpp
File metadata and controls
125 lines (109 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "Animation.hpp"
#include "Model.hpp"
Animation::Animation() noexcept {}
void Animation::setStateAtTime(Model& aModel, const float aTime) noexcept {
//impt fix \w AI
//GLTF spec is an asshole: animations matrices shall not be replaced, section 3.5.3
//animation replaces only TRS, not all the parents and stuff
// only calc and update local matrices of nodes
// rest done in model class
std::unordered_map<size_t, TRSOverrideData> data;
data.reserve(this->mSamplers.size());
for (uint64_t i = 0; i < this->mSamplers.size(); i++) {
TRSData trs = this->getLocalSamplerTransform(i, aTime);
TRSOverrideData& animData = data[this->mSamplers[i].nodeIndex];
switch (trs.type) {
case (fastgltf::AnimationPath::Translation):
animData.t = trs.t;
animData.hasTranslation = true;
break;
case (fastgltf::AnimationPath::Rotation):
animData.r = trs.r;
animData.hasRotation = true;
break;
case (fastgltf::AnimationPath::Scale):
animData.s = trs.s;
animData.hasScale = true;
break;
default:
std::cerr << "Applying weight animation is not supported! (" << (uint16_t)trs.type << ")\n";
break;
}
}
for(auto& [nodeIndex, animData] : data) {
auto& node = aModel.mNodes[nodeIndex];
glm::vec3 tra(0.0);
glm::quat rot(1, 0, 0, 0);
glm::vec3 scl(1.0);
glm::vec3 skew(1.0); //unused
glm::vec4 perspective(1, 0, 0, 0); //unused
//TODO precalculate
glm::decompose(node.transformMatrix, scl, rot, tra, skew, perspective);
if (animData.hasTranslation) tra = animData.t;
if (animData.hasRotation) rot = animData.r;
if (animData.hasScale) scl = animData.s;
//TRS!
node.localMatrix = glm::translate(glm::mat4(1.0f), tra)
* glm::mat4_cast(rot)
* glm::scale(glm::mat4(1.0f), scl);
}
}
float Animation::getMaxTime() const noexcept {
return this->mMaxTime;
}
Animation::~Animation() noexcept {}
float Animation::lerp(float aLast, float aNext, float aCurrent) noexcept {
if(aCurrent <= aLast) return 0.0; //should not happen
if(aCurrent >= aNext) return 1.0;
return ((float)aCurrent - (float)aLast)/((float)aNext - (float)aLast); //should be in range 0-1
}
uint64_t Animation::getIndex(const SamplerData& aSampler, const float aTime) noexcept {
for(uint64_t i = 0; i < aSampler.time.size()-1; i++) {
if(aTime < aSampler.time[i+1]) return i;
}
return aSampler.time.back();
}
glm::vec3 Animation::interpolatePosition(const SamplerData& aSampler, const float aTime) noexcept {
uint64_t start = getIndex(aSampler, aTime);
uint64_t end = start+1;
float weight = lerp(aSampler.time[start], aSampler.time[end], aTime);
glm::vec3 position = glm::vec3(glm::mix(aSampler.value[start], aSampler.value[end], weight));
return position;
}
glm::quat Animation::interpolateRotation(const SamplerData& aSampler, const float aTime) noexcept {
uint64_t start = getIndex(aSampler, aTime);
uint64_t end = start+1;
float weight = lerp(aSampler.time[start], aSampler.time[end], aTime);
glm::quat qstart = glm::quat(aSampler.value[start].w, aSampler.value[start].x, aSampler.value[start].y, aSampler.value[start].z);
glm::quat qend = glm::quat(aSampler.value[end].w, aSampler.value[end].x, aSampler.value[end].y, aSampler.value[end].z);
glm::quat rotation = glm::normalize(glm::slerp(qstart, qend, weight));
return rotation;
}
glm::vec3 Animation::interpolateScale(const SamplerData& aSampler, const float aTime) noexcept {
uint64_t start = getIndex(aSampler, aTime);
uint64_t end = start+1;
float weight = lerp(aSampler.time[start], aSampler.time[end], aTime);
glm::vec3 scale = glm::vec3(glm::mix(aSampler.value[start], aSampler.value[end], weight));
return scale;
}
TRSData Animation::getLocalSamplerTransform(const uint64_t aSamplerId, const float aTime) noexcept {
auto& sampler = this->mSamplers[aSamplerId];
TRSData result;
result.type = sampler.type;
//TRS enforced by sampler order
switch(sampler.type) {
case(fastgltf::AnimationPath::Translation):
result.t = interpolatePosition(sampler, aTime);
break;
case(fastgltf::AnimationPath::Rotation):
result.r = interpolateRotation(sampler, aTime);
break;
case(fastgltf::AnimationPath::Scale):
result.s = interpolateScale(sampler, aTime);
break;
default:
std::cerr << "Weight animation is not supported!\n";
break;
}
return result;
}