Skip to content

Commit 68deb77

Browse files
Improve animation system and add capsule model
Added a new capsule.glb model asset. Refactored animation data structures to use pointers for frames, added animation length tracking, and improved channel type handling. Updated GfxAnimator to support animation playback with time looping, correct interpolation, and debug bone visualization. Fixed local transform calculation order and various minor bugs in animation and skeleton code.
1 parent a1925d5 commit 68deb77

3 files changed

Lines changed: 88 additions & 45 deletions

File tree

default_assets/models/capsule.glb

19.6 KB
Binary file not shown.

include/borealis/gfx/model.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,17 @@ namespace brl
131131
};
132132

133133
struct Channel {
134-
int boneIndex;
134+
int boneIndex = -1;
135135
ChannelInterpolation interpolation;
136136
ChannelType type;
137137

138-
std::vector<AnimationFrame> frames;
138+
std::vector<AnimationFrame*> frames;
139139
};
140140

141141
std::string name;
142142

143143
std::vector<Channel> channels;
144+
float length = 0;
144145

145146
};
146147

@@ -261,8 +262,8 @@ namespace brl
261262

262263
GfxAnimation* animation;
263264

264-
GfxAnimator();
265265

266+
void start() override;
266267
void update() override;
267268

268269
private:

src/brl/gfx/model.cpp

Lines changed: 84 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
#include "borealis/gfx/model.hpp"
1+
#include "borealis/gfx/model.hpp"
22

33
#define TINYGLTF_IMPLEMENTATION
44
#define TINYGLTF_NO_EXTERNAL_IMAGE
55
#define TINYGLTF_NO_STB_IMAGE_WRITE
66
#include <tiny_gltf.h>
77

8+
#include "borealis/debug/debug.hpp"
89
#include "borealis/gfx/engine.hpp"
910
#include "borealis/gfx/shader.hpp"
1011
#include "glm/gtx/matrix_decompose.hpp"
@@ -368,28 +369,26 @@ brl::GfxModel::GfxModel(std::string path)
368369
// Joint IDs can be stored as different types
369370
if (jnt_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
370371
{
371-
// 8-bit unsigned integers
372+
// 8-bit unsigned integers (VEC4 = 4 bytes)
373+
const size_t stride = jnt_bufferView.byteStride > 0 ? jnt_bufferView.byteStride : 4;
372374
for (size_t i = 0; i < jnt_accessor.count; ++i)
373375
{
374376
const uint8_t* data = reinterpret_cast<const uint8_t*>(
375-
&jnt_buffer.data[jnt_bufferView.byteOffset + i * jnt_accessor.byteOffset]);
377+
&jnt_buffer.data[jnt_bufferView.byteOffset + jnt_accessor.byteOffset + i * stride]);
376378
vertices[i].boneIds = glm::uvec4(data[0], data[1], data[2], data[3]);
377379
}
378380
}
379381
else if (jnt_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
380382
{
381-
// 16-bit unsigned integers (most common)
383+
// 16-bit unsigned integers (VEC4 = 8 bytes)
384+
const size_t stride = jnt_bufferView.byteStride > 0 ? jnt_bufferView.byteStride : 8;
382385
for (size_t i = 0; i < jnt_accessor.count; ++i)
383386
{
384387
const uint16_t* data = reinterpret_cast<const uint16_t*>(
385-
&jnt_buffer.data[jnt_bufferView.byteOffset + i * jnt_accessor.byteOffset]);
388+
&jnt_buffer.data[jnt_bufferView.byteOffset + jnt_accessor.byteOffset + i * stride]);
386389
vertices[i].boneIds = glm::uvec4(data[0], data[1], data[2], data[3]);
387390
}
388391
}
389-
else
390-
{
391-
// no joints
392-
}
393392

394393
auto attribBuffer = new GfxAttribBuffer();
395394

@@ -600,6 +599,8 @@ brl::GfxModel::GfxModel(std::string path)
600599

601600
GfxAnimation* animation = new GfxAnimation();
602601

602+
animation->name = anim.name;
603+
603604
for (tinygltf::AnimationChannel channel : anim.channels) {
604605

605606
GfxAnimation::Channel animChannel{};
@@ -628,13 +629,22 @@ brl::GfxModel::GfxModel(std::string path)
628629
if (targetBone == -1 || targetSkin == -1)
629630
continue;
630631

632+
animChannel.boneIndex = targetBone;
633+
631634
if (sampler.interpolation == "LINEAR")
632635
animChannel.interpolation = GfxAnimation::LINEAR;
633636
if (sampler.interpolation == "STEP")
634637
animChannel.interpolation = GfxAnimation::STEP;
635638
if (sampler.interpolation == "CUBICSPLINE")
636639
animChannel.interpolation = GfxAnimation::CUBICSPLINE;
637640

641+
if (channel.target_path == "translation")
642+
animChannel.type = GfxAnimation::TRANSLATION;
643+
if (channel.target_path == "rotation")
644+
animChannel.type = GfxAnimation::ROTATION;
645+
if (channel.target_path == "scale")
646+
animChannel.type = GfxAnimation::SCALE;
647+
638648
const tinygltf::Accessor& inputAccessor = model.accessors[sampler.input];
639649
const tinygltf::Accessor& outputAccessor = model.accessors[sampler.output];
640650

@@ -657,15 +667,20 @@ brl::GfxModel::GfxModel(std::string path)
657667
float frame = times[i];
658668
glm::vec3 value = {values[i * 3 + 0], values[i * 3 + 1], values[i * 3 + 2]};
659669

660-
animChannel.frames.push_back(GfxAnimation::Vec3AnimationFrame{frame,value});
670+
animation->length = glm::max(animation->length, frame);
671+
672+
673+
animChannel.frames.push_back(new GfxAnimation::Vec3AnimationFrame{frame,value});
661674
}
662675
} else if (animChannel.type == GfxAnimation::ROTATION)
663676
{
664677
for (std::size_t i = 0; i < frameCount; ++i) {
665678
float frame = times[i];
666-
glm::quat value = {values[i * 4 + 0], values[i * 4 + 1], values[i * 4 + 2], values[i*4+3]};
679+
glm::quat value = {values[i * 4 + 3], values[i * 4 + 0], values[i * 4 + 1], values[i * 4 + 2]};
667680

668-
animChannel.frames.push_back(GfxAnimation::QuatAnimationFrame{frame,value});
681+
animation->length = glm::max(animation->length, frame);
682+
683+
animChannel.frames.push_back(new GfxAnimation::QuatAnimationFrame{frame,value});
669684
}
670685
}
671686

@@ -740,18 +755,12 @@ void brl::GfxMeshRenderer::lateUpdate()
740755
}
741756
}
742757

743-
744-
745758
glm::mat4 brl::GfxBone::calculateLocalTransform()
746759
{
747-
glm::mat4 t(1.0);
748-
749-
t = translate(t, position);
750-
t *= glm::toMat4(rotation);
751-
t = glm::scale(t, scale);
752-
753-
754-
return t;
760+
glm::mat4 t = glm::translate(glm::mat4(1.0), position);
761+
glm::mat4 r = glm::toMat4(rotation);
762+
glm::mat4 s = glm::scale(glm::mat4(1.0), scale);
763+
return t * r * s; // T * R * S (correct order)
755764
}
756765

757766
void brl::GfxBone::validate()
@@ -764,6 +773,8 @@ void brl::GfxBone::apply()
764773
lastCheckedPosition = position;
765774
lastCheckedRotation = rotation;
766775
lastCheckedScale = scale;
776+
777+
changed = false;
767778
}
768779

769780
void brl::GfxSkin::initialize()
@@ -844,8 +855,6 @@ void brl::GfxSkeleton::_calcTransform(brl::GfxBone* bone, const glm::mat4& paren
844855
{
845856
_calcTransform(bones[child], bone->worldMatrix, child, _changed);
846857
}
847-
848-
bone->changed = false;
849858
}
850859

851860
brl::GfxSkinnedMeshRenderer::GfxSkinnedMeshRenderer()
@@ -884,48 +893,81 @@ void brl::GfxSkinnedMeshRenderer::lateUpdate()
884893
}
885894
}
886895

896+
void brl::GfxAnimator::start()
897+
{
898+
EcsEntity::start();
899+
900+
model = getEntityInParent<GfxModelEntity>();
901+
}
902+
887903
void brl::GfxAnimator::update()
888904
{
905+
EcsEntity::update();
906+
889907
const auto& skeleton = model->skeletons[0];
890908

891909
time += GfxEngine::instance->getDeltaTime();
892910

911+
if (time > animation->length)
912+
{
913+
time = 0;
914+
}
915+
893916
for (int i = 0; i < animation->channels.size(); i++)
894917
{
895918
const auto& channel = animation->channels[i];
896919
GfxBone* bone = skeleton->bones[channel.boneIndex];
897920

898921
int key = -1;
899-
for (int j = 0; j < channel.frames.size()-1; j++)
922+
for (int j = 0; j < channel.frames.size() - 1; j++)
900923
{
901-
if (time < channel.frames[j] ) {
924+
if (time < channel.frames[j+1]->time)
925+
{
902926
key = j;
903927
break;
904928
}
905929
}
906930

907-
// add interpolation
908-
if (channel.type == GfxAnimation::TRANSLATION || channel.type == GfxAnimation::SCALE) {
931+
if (key == -1)
932+
continue;
909933

910-
const Vec3AnimationFrame& frame = channel.frames[key];
911-
const Vec3AnimationFrame& nextFrame = channel.frames[key+1];
912934

913-
if (channel.type == GfxAnimation::TRANSLATION) {
914-
bone->position = frame.value;
915-
} else {
916-
bone->scale = frame.value;
935+
// add interpolation
936+
if (channel.type == GfxAnimation::TRANSLATION || channel.type == GfxAnimation::SCALE)
937+
{
938+
939+
const GfxAnimation::Vec3AnimationFrame* frame =
940+
static_cast<const GfxAnimation::Vec3AnimationFrame*>(channel.frames[key]);
941+
const GfxAnimation::Vec3AnimationFrame* nextFrame =
942+
static_cast<const GfxAnimation::Vec3AnimationFrame*>(channel.frames[key + 1]);
943+
944+
if (channel.type == GfxAnimation::TRANSLATION)
945+
{
946+
bone->position = frame->value;
947+
}
948+
else
949+
{
950+
bone->scale = frame->value;
917951
}
918-
} else {
919-
const QuatAnimationFrame& frame = channel.frames[key];
920-
const QuatAnimationFrame& nextFrame = channel.frames[key+1];
952+
}
953+
else
954+
{
955+
const GfxAnimation::QuatAnimationFrame* frame =
956+
static_cast<const GfxAnimation::QuatAnimationFrame*>(channel.frames[key]);
957+
const GfxAnimation::QuatAnimationFrame* nextFrame =
958+
static_cast<const GfxAnimation::QuatAnimationFrame*>(channel.frames[key + 1]);
921959

922-
bone->rotation = frame.value;
960+
bone->rotation = glm::normalize(frame->value);
923961
}
924962

925963
bone->validate();
926964
}
927965

928-
929-
930-
931-
}
966+
for (const auto& bone : skeleton->bones)
967+
{
968+
for (int childIndex : bone->children)
969+
{
970+
brl_debug::drawLine(bone->position, skeleton->bones[childIndex]->position);
971+
}
972+
}
973+
}

0 commit comments

Comments
 (0)