Skip to content

Commit 3bec32f

Browse files
committed
refactor(animation): update animation system and remove skeleton.cpp
1 parent 0a8fe3b commit 3bec32f

13 files changed

Lines changed: 203 additions & 234 deletions

File tree

CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,6 @@ add_executable(${PROJECT_NAME}
240240

241241
src/common/model/model.cpp
242242

243-
src/common/animation/skeleton.cpp
244-
245243
src/common/texture/sampler.cpp
246244
src/common/texture/texture-utils.cpp
247245
src/common/texture/screenshot.cpp

config/playgrounds/animation.jsonc

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"start-scene": "play",
2+
"start-scene": "menu",
33
"window": {
44
"title": "Default Game Window",
55
"size": {
@@ -30,16 +30,22 @@
3030
},
3131
"textures": {
3232
"moon": "assets/textures/moon.jpg",
33-
"grass": "assets/textures/grass_ground_d.jpg"
33+
"grass": "assets/textures/grass_ground_d.jpg",
34+
"wood": "assets/textures/wood.jpg",
35+
"glass": "assets/textures/glass-panels.png",
36+
"monkey": "assets/textures/monkey.png"
3437
},
3538
"meshes": {
36-
"plane": "assets/models/plane.obj",
37-
"sphere": "assets/models/sphere.obj",
3839
"cube": "assets/models/cube.obj",
39-
"monkey": "assets/models/monkey.obj"
40+
"monkey": "assets/models/monkey.obj",
41+
"plane": "assets/models/plane.obj",
42+
"sphere": "assets/models/sphere.obj"
4043
},
4144
"samplers": {
4245
"default": {},
46+
"pixelated": {
47+
"MAG_FILTER": "GL_NEAREST"
48+
},
4349
"ground_tiled": {
4450
"MIN_FILTER": "GL_LINEAR_MIPMAP_LINEAR",
4551
"MAG_FILTER": "GL_LINEAR",
@@ -104,6 +110,28 @@
104110
},
105111
"tint": [0.45, 0.4, 0.5, 1.0]
106112
},
113+
"glass": {
114+
"type": "textured",
115+
"shader": "textured",
116+
"pipelineState": {
117+
"faceCulling": {
118+
"enabled": false
119+
},
120+
"depthTesting": {
121+
"enabled": true
122+
},
123+
"blending": {
124+
"enabled": true,
125+
"sourceFactor": "GL_SRC_ALPHA",
126+
"destinationFactor": "GL_ONE_MINUS_SRC_ALPHA"
127+
},
128+
"depthMask": false
129+
},
130+
"transparent": true,
131+
"tint": [1.0, 1.0, 1.0, 1.0],
132+
"texture": "glass",
133+
"sampler": "pixelated"
134+
},
107135
"grass": {
108136
"type": "textured",
109137
"shader": "textured",
@@ -152,8 +180,9 @@
152180
},
153181
"models": {
154182
"drone": "assets/gltf/mech_drone/mech_drone.glb",
183+
"map": "assets/gltf/map/map.glb",
155184
"gun": "assets/gltf/weapons/rifle.glb",
156-
"snake": "assets/tmp/Snake.glb"
185+
"alistar": "assets/gltf/enemies/mundo/corporate_mundo.glb"
157186
}
158187
},
159188
"game": {
@@ -267,42 +296,28 @@
267296
},
268297
{
269298
"type": "Collider",
270-
"shape": "Capsule",
271-
"height": 3.6,
272-
"radius": 0.4,
273-
"layer": "player"
299+
"layer": "player",
300+
"radius": 0.45,
301+
"height": 1.8
274302
},
275303
{
276304
"type": "light",
277305
"lightType": "spot",
278-
"color": [1, 1, 1],
279-
"attenuation": [1.0, 0.1, 0.1],
280-
"spotAngles": [12, 20]
306+
"color": [3, 3, 3],
307+
"attenuation": [1.0, 0.22, 0.2],
308+
"spotAngles": [13, 20]
281309
}
282310
],
283311
"children": [
284312
{
285-
"position": [1, -1, -2],
286-
"rotation": [0, 0, 0],
287-
"scale": [0.3, 0.3, 0.3],
313+
"position": [1, -1, -1],
314+
"rotation": [45, 45, 0],
315+
"scale": [0.1, 0.1, 1.0],
288316
"components": [
289317
{
290-
"type": "Model Renderer",
291-
"model": "gun"
292-
}
293-
],
294-
"children": [
295-
{
296-
"position": [0, 0, 0],
297-
"components": [
298-
{
299-
"type": "light",
300-
"lightType": "spot",
301-
"color": [1, 0.8, 0.6],
302-
"attenuation": [1.0, 0.14, 0.07],
303-
"spotAngles": [15, 20]
304-
}
305-
]
318+
"type": "Mesh Renderer",
319+
"mesh": "cube",
320+
"material": "metal"
306321
}
307322
]
308323
}
@@ -322,47 +337,32 @@
322337
]
323338
},
324339
{
325-
"position": [2, 1, -2],
340+
"position": [2, 4, -2],
326341
"scale": [5, 5, 5],
327-
"components": [
328-
{
329-
"type": "Model Renderer",
330-
"model": "drone"
331-
}
332-
]
333-
},
334-
{
335-
"name": "moon (test lighting)",
336-
"position": [-5.0, 5.0, -5.0],
337342
"components": [
338343
{
339344
"type": "Mesh Renderer",
340-
"mesh": "sphere",
341-
"material": "moon"
342-
},
343-
{
344-
"type": "light",
345-
"lightType": "point",
346-
"color": [1, 1, 1],
347-
"attenuation": [1.0, 0.14, 0.07]
345+
"mesh": "monkey",
346+
"material": "monkey"
348347
}
349348
]
350349
},
351350
{
352-
"name": "snake",
353-
"position": [0, 0, 0],
351+
"name": "test enemy",
352+
"position": [10, 0, 10],
353+
"scale": [0.01, 0.01, 0.01],
354354
"components": [
355355
{
356356
"type": "Model Renderer",
357-
"model": "snake"
357+
"model": "alistar"
358358
},
359359
{
360360
"type": "Animation",
361-
"model": "snake",
362-
"clip": "Snake_Walk",
361+
"model": "alistar",
362+
"clip": "Run01",
363+
"loop": true,
363364
"speed": 1.0,
364-
"autoplay": true,
365-
"loop": true
365+
"autoplay": true
366366
}
367367
]
368368
}

src/common/animation/animation.hpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace our {
1616
class Animation {
1717
public:
1818
std::string name;
19-
std::unordered_map<BoneID, Bone> bones;
19+
std::unordered_map<BoneID, BoneAnimation> bones;
2020
Skeleton& skeleton;
2121
float duration; // in ticks
2222
float ticksPerSecond;
@@ -28,19 +28,18 @@ namespace our {
2828
aiNodeAnim* channel = anim->mChannels[i];
2929
std::string boneName = channel->mNodeName.C_Str();
3030

31-
// skip nodes that aren't bones (IK targets, camera nodes, etc.)
32-
if (!skeleton.hasBone(boneName)) continue;
33-
34-
BoneID id = skeleton.getBoneID(boneName);
35-
bones.emplace(id, Bone(boneName, id, channel));
31+
// find or create because some bones are not referenced in the meshes but are still animated
32+
// they don't contribute to mesh weights but they still affect the bones after them in the hierarchy
33+
BoneID id = skeleton.findOrCreateBone(boneName, glm::mat4(1.0f));
34+
bones.emplace(id, BoneAnimation(boneName, id, channel));
3635
}
3736
}
38-
Bone& findBone(const std::string& name) {
37+
BoneAnimation& findBone(const std::string& name) {
3938
auto it = bones.find(skeleton.getBoneID(name));
4039
if (it != bones.end()) {
4140
return it->second;
4241
}
43-
throw std::runtime_error("Bone not found: " + name);
42+
throw std::runtime_error("BoneAnimation not found: " + name);
4443
}
4544
};
4645
} // namespace our

src/common/animation/animator.hpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,53 @@ namespace our {
1010
const Animation* currentAnimation;
1111
float currentTime; // in ticks
1212
std::vector<glm::mat4> finalBoneMatrices;
13-
float deltaTime;
13+
bool loop;
1414

15-
void computeBoneTransform(const SkeletonNode& node, glm::mat4 parentTransform) {
15+
void computeBoneTransform(const std::vector<SkeletonNode>& nodes) {
1616
const Skeleton& skeleton = currentAnimation->skeleton;
17-
glm::mat4 nodeTransform = node.localTransform; // fallback: bind pose
17+
std::vector<glm::mat4> globalTransforms(nodes.size());
1818

19-
if (skeleton.hasBone(node.name)) {
19+
for (int i = 0; i < (int)nodes.size(); i++) {
20+
const auto& node = nodes[i];
21+
22+
// animated local transform, fallback to bind pose
23+
glm::mat4 localTransform = node.localTransform;
2024
BoneID id = skeleton.getBoneID(node.name);
21-
auto it = currentAnimation->bones.find(id);
22-
if (it != currentAnimation->bones.end()) {
23-
nodeTransform = it->second.interpolate(currentTime);
25+
if (id >= 0) {
26+
auto it = currentAnimation->bones.find(id);
27+
if (it != currentAnimation->bones.end()) localTransform = it->second.interpolate(currentTime);
2428
}
25-
}
2629

27-
glm::mat4 globalTransform = parentTransform * nodeTransform;
30+
// accumulate from parent
31+
if (node.parentIndex < 0)
32+
globalTransforms[i] = localTransform;
33+
else
34+
globalTransforms[i] = globalTransforms[node.parentIndex] * localTransform;
2835

29-
if (skeleton.hasBone(node.name)) {
30-
BoneID id = skeleton.getBoneID(node.name);
31-
glm::mat4 offset = skeleton.getOffsetMatrix(node.name);
32-
if (id >= 0 && id < static_cast<BoneID>(finalBoneMatrices.size())) {
33-
finalBoneMatrices[id] = skeleton.getGlobalInverseTransform() * globalTransform * offset;
34-
}
36+
if (id >= 0 && id < (BoneID)finalBoneMatrices.size())
37+
finalBoneMatrices[id] = skeleton.getGlobalInverseTransform() * globalTransforms[i] *
38+
skeleton.getOffsetMatrix(node.name);
3539
}
36-
37-
for (const SkeletonNode& child : node.children) computeBoneTransform(child, globalTransform);
3840
}
3941

4042
public:
4143
Animator() : finalBoneMatrices(MAX_BONES, glm::mat4(1.0f)) {}
4244

43-
void play(const Animation* anim) {
45+
void play(const Animation* anim, bool loop = true) {
4446
currentAnimation = anim;
4547
currentTime = 0.0f;
48+
this->loop = loop;
4649
}
4750

48-
void update(float deltaTime, bool loop = true) {
51+
void update(float deltaTime) {
4952
if (!currentAnimation) return;
5053
currentTime += currentAnimation->ticksPerSecond * deltaTime;
5154
if (loop) {
52-
currentTime = fmod(currentTime, currentAnimation->duration);
55+
currentTime = std::fmod(currentTime, currentAnimation->duration);
5356
} else {
5457
currentTime = std::min(currentTime, currentAnimation->duration);
5558
}
56-
computeBoneTransform(currentAnimation->skeleton.getRoot(), glm::mat4(1.0f));
59+
computeBoneTransform(currentAnimation->skeleton.getNodes());
5760
}
5861

5962
const std::vector<glm::mat4>& getFinalBoneMatrices() const {

0 commit comments

Comments
 (0)