Browse Source

Add support for skeletal animations

master
C. J. Howard 7 years ago
parent
commit
b996c43f5f
6 changed files with 179 additions and 23 deletions
  1. +1
    -1
      data
  2. +1
    -1
      lib/emergent
  3. +25
    -0
      src/game/ant.cpp
  4. +1
    -0
      src/game/ant.hpp
  5. +126
    -20
      src/model-loader.cpp
  6. +25
    -1
      src/model-loader.hpp

+ 1
- 1
data

@ -1 +1 @@
Subproject commit e0fb2511f4d08bb4823535ebdaa79de3cf2caf59
Subproject commit 11f999abf6d47962610f6c9696a8d4d4ee2a1bcb

+ 1
- 1
lib/emergent

@ -1 +1 @@
Subproject commit 0d4b84100382a6053dfd2da5e7707bc28477ac87
Subproject commit f07060a2fd956170b046bf412fa3b9b73b06f320

+ 25
- 0
src/game/ant.cpp View File

@ -36,6 +36,8 @@ Ant::Ant(Colony* colony):
modelInstance.setModel(colony->getAntModel()); modelInstance.setModel(colony->getAntModel());
modelInstance.setPose(pose); modelInstance.setPose(pose);
animationTime = 0.0f;
} }
Ant::~Ant() Ant::~Ant()
@ -45,6 +47,7 @@ Ant::~Ant()
void Ant::rotateHead() void Ant::rotateHead()
{ {
/*
const Bone* headBone = pose->getSkeleton()->getBone("left-flagellum"); const Bone* headBone = pose->getSkeleton()->getBone("left-flagellum");
if (headBone != nullptr) if (headBone != nullptr)
{ {
@ -56,6 +59,28 @@ void Ant::rotateHead()
pose->setRelativeTransform(boneIndex, transform); pose->setRelativeTransform(boneIndex, transform);
pose->concatenate(); pose->concatenate();
} }
*/
const Animation* animation = pose->getSkeleton()->getAnimation("eat");
if (animation != nullptr)
{
for (std::size_t i = 0; i < animation->getChannelCount(); ++i)
{
const AnimationChannel* channel = animation->getChannel(i);
std::size_t boneIndex = channel->getChannelID();
Transform transform = channel->interpolateBoundingKeyFrames(animationTime);
pose->setRelativeTransform(channel->getChannelID(), transform);
}
pose->concatenate();
animationTime += 0.5f;
if (animationTime > animation->getEndTime())
{
animationTime = animation->getStartTime();
}
}
} }
void Ant::move(const Vector3& velocity) void Ant::move(const Vector3& velocity)

+ 1
- 0
src/game/ant.hpp View File

@ -96,6 +96,7 @@ private:
Colony* colony; Colony* colony;
Ant::State state; Ant::State state;
float animationTime;
Transform transform; Transform transform;
ModelInstance modelInstance; ModelInstance modelInstance;

+ 126
- 20
src/model-loader.cpp View File

@ -174,35 +174,104 @@ Model* ModelLoader::load(const std::string& filename)
{ {
// Allocate skeleton data // Allocate skeleton data
skeletonData = new SkeletonData(); skeletonData = new SkeletonData();
skeletonData->animations = nullptr;
// Read bone count // Read bone count
read16(&skeletonData->boneCount, &bufferOffset); read16(&skeletonData->boneCount, &bufferOffset);
// Allocate bones // Allocate bones
skeletonData->boneData = new BoneData[skeletonData->boneCount];
skeletonData->bones = new BoneData[skeletonData->boneCount];
// Read bones // Read bones
for (std::size_t i = 0; i < skeletonData->boneCount; ++i) for (std::size_t i = 0; i < skeletonData->boneCount; ++i)
{ {
BoneData* boneData = &skeletonData->boneData[i];
boneData->children = nullptr;
BoneData* bone = &skeletonData->bones[i];
bone->children = nullptr;
readString(&boneData->name, &bufferOffset);
read16(&boneData->parent, &bufferOffset);
read16(&boneData->childCount, &bufferOffset);
boneData->children = new std::uint16_t[boneData->childCount];
for (std::size_t j = 0; j < boneData->childCount; ++j)
readString(&bone->name, &bufferOffset);
read16(&bone->parent, &bufferOffset);
read16(&bone->childCount, &bufferOffset);
bone->children = new std::uint16_t[bone->childCount];
for (std::size_t j = 0; j < bone->childCount; ++j)
{ {
read16(&boneData->children[j], &bufferOffset);
read16(&bone->children[j], &bufferOffset);
}
read32(&bone->translation.x, &bufferOffset);
read32(&bone->translation.y, &bufferOffset);
read32(&bone->translation.z, &bufferOffset);
read32(&bone->rotation.w, &bufferOffset);
read32(&bone->rotation.x, &bufferOffset);
read32(&bone->rotation.y, &bufferOffset);
read32(&bone->rotation.z, &bufferOffset);
read32(&bone->length, &bufferOffset);
}
// Read animation count
read16(&skeletonData->animationCount, &bufferOffset);
if (skeletonData->animationCount != 0)
{
// Allocate animations
skeletonData->animations = new AnimationData[skeletonData->animationCount];
// Read animations
for (std::size_t i = 0; i < skeletonData->animationCount; ++i)
{
AnimationData* animation = &skeletonData->animations[i];
// Read animation name
readString(&animation->name, &bufferOffset);
// Read time frame
read32(&animation->startTime, &bufferOffset);
read32(&animation->endTime, &bufferOffset);
// Read channel count
read16(&animation->channelCount, &bufferOffset);
// Allocate channels
animation->channels = new ChannelData[animation->channelCount];
// Read channels
for (std::size_t j = 0; j < animation->channelCount; ++j)
{
ChannelData* channel = &animation->channels[j];
// Read channel ID
read16(&channel->id, &bufferOffset);
// Read keyframe count
read16(&channel->keyFrameCount, &bufferOffset);
// Allocate keyframes
channel->keyFrames = new KeyFrameData[channel->keyFrameCount];
// Read keyframes
for (std::size_t k = 0; k < channel->keyFrameCount; ++k)
{
KeyFrameData* keyFrame = &channel->keyFrames[k];
// Read keyframe time
read32(&keyFrame->time, &bufferOffset);
// Read keyframe translation
read32(&keyFrame->transform.translation.x, &bufferOffset);
read32(&keyFrame->transform.translation.y, &bufferOffset);
read32(&keyFrame->transform.translation.z, &bufferOffset);
// Read keyframe rotation
read32(&keyFrame->transform.rotation.w, &bufferOffset);
read32(&keyFrame->transform.rotation.x, &bufferOffset);
read32(&keyFrame->transform.rotation.y, &bufferOffset);
read32(&keyFrame->transform.rotation.z, &bufferOffset);
// Read keyframe scale
read32(&keyFrame->transform.scale.x, &bufferOffset);
read32(&keyFrame->transform.scale.y, &bufferOffset);
read32(&keyFrame->transform.scale.z, &bufferOffset);
}
}
} }
read32(&boneData->translation.x, &bufferOffset);
read32(&boneData->translation.y, &bufferOffset);
read32(&boneData->translation.z, &bufferOffset);
read32(&boneData->rotation.w, &bufferOffset);
read32(&boneData->rotation.x, &bufferOffset);
read32(&boneData->rotation.y, &bufferOffset);
read32(&boneData->rotation.z, &bufferOffset);
read32(&boneData->length, &bufferOffset);
} }
} }
@ -339,11 +408,35 @@ Model* ModelLoader::load(const std::string& filename)
Skeleton* skeleton = new Skeleton(); Skeleton* skeleton = new Skeleton();
// Construct bone hierarchy from bone data // Construct bone hierarchy from bone data
constructBoneHierarchy(skeleton->getRootBone(), skeletonData->boneData, 0);
constructBoneHierarchy(skeleton->getRootBone(), skeletonData->bones, 0);
// Calculate bind pose // Calculate bind pose
skeleton->calculateBindPose(); skeleton->calculateBindPose();
// Create animations
for (std::size_t i = 0; i < skeletonData->animationCount; ++i)
{
AnimationData* animationData = &skeletonData->animations[i];
Animation* animation = new Animation();
animation->setName(animationData->name);
animation->setTimeFrame(animationData->startTime, animationData->endTime);
for (std::size_t j = 0; j < animationData->channelCount; ++j)
{
ChannelData* channelData = &animationData->channels[j];
AnimationChannel* channel = animation->createChannel(channelData->id);
for (std::size_t k = 0; k < channelData->keyFrameCount; ++k)
{
KeyFrameData* keyFrameData = &channelData->keyFrames[k];
KeyFrame* keyFrame = channel->insertKeyFrame(keyFrameData->time);
keyFrame->setTransform(keyFrameData->transform);
}
}
// Add animation to skeleton
skeleton->addAnimation(animation);
}
// Add skeleton to model // Add skeleton to model
model->setSkeleton(skeleton); model->setSkeleton(skeleton);
} }
@ -359,9 +452,22 @@ Model* ModelLoader::load(const std::string& filename)
{ {
for (std::size_t i = 0; i < skeletonData->boneCount; ++i) for (std::size_t i = 0; i < skeletonData->boneCount; ++i)
{ {
delete[] skeletonData->boneData[i].children;
delete[] skeletonData->bones[i].children;
}
delete[] skeletonData->bones;
for (std::size_t i = 0; i < skeletonData->animationCount; ++i)
{
AnimationData* animation = &skeletonData->animations[i];
for (std::size_t j = 0; j < animation->channelCount; ++j)
{
delete[] animation->channels[j].keyFrames;
}
delete[] animation->channels;
} }
delete[] skeletonData->boneData;
delete[] skeletonData->animations;
delete skeletonData; delete skeletonData;
} }

+ 25
- 1
src/model-loader.hpp View File

@ -74,10 +74,34 @@ private:
float length; float length;
}; };
struct KeyFrameData
{
float time;
Transform transform;
};
struct ChannelData
{
std::uint16_t id;
std::uint16_t keyFrameCount;
KeyFrameData* keyFrames;
};
struct AnimationData
{
std::string name;
float startTime;
float endTime;
std::uint16_t channelCount;
ChannelData* channels;
};
struct SkeletonData struct SkeletonData
{ {
std::uint16_t boneCount; std::uint16_t boneCount;
BoneData* boneData;
BoneData* bones;
std::uint16_t animationCount;
AnimationData* animations;
}; };
static void constructBoneHierarchy(Bone* bone, const BoneData* data, std::uint16_t index); static void constructBoneHierarchy(Bone* bone, const BoneData* data, std::uint16_t index);

Loading…
Cancel
Save