Skip to content

Commit

Permalink
animation: refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
furkansarihan committed Nov 29, 2023
1 parent 3a4beee commit c6318dc
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 85 deletions.
16 changes: 8 additions & 8 deletions src/animation/animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

#include "animation.h"

Animation::Animation(const std::string &animationName, Model *model, bool timed)
: m_name(animationName),
m_timed(timed)
Animation::Animation(const std::string &animationName, Model *model)
: m_name(animationName)
{
const aiScene *scene = model->m_scene;
assert(scene && scene->mRootNode);
Expand All @@ -21,6 +20,7 @@ Animation::Animation(const std::string &animationName, Model *model, bool timed)
}
}

// TODO: ?
if (animation == nullptr)
{
std::cout << "Animation: can not found an animation with name: " << animationName << std::endl;
Expand All @@ -33,11 +33,11 @@ Animation::Animation(const std::string &animationName, Model *model, bool timed)
// std::cout << "Animation: mNumChannels: " << animation->mNumChannels << std::endl
// << std::endl;

m_RootNode = new AssimpNodeData();
m_rootNode = new AssimpNodeData();

m_Duration = animation->mDuration;
m_TicksPerSecond = animation->mTicksPerSecond;
readHierarchy(m_RootNode, scene->mRootNode);
m_duration = animation->mDuration;
m_ticksPerSecond = animation->mTicksPerSecond;
readHierarchy(m_rootNode, scene->mRootNode);
readBones(animation, *model);
}

Expand Down Expand Up @@ -96,7 +96,7 @@ void Animation::readBones(const aiAnimation *animation, Model &model)
m_bones[boneName] = bone;
}

m_BoneInfoMap = boneInfoMap;
m_boneInfoMap = boneInfoMap;
}

// TODO: only read bones?
Expand Down
12 changes: 5 additions & 7 deletions src/animation/animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,17 @@ class Animation
{
public:
std::string m_name;
float m_Duration;
float m_playbackSpeed = 1.f;
int m_TicksPerSecond;
bool m_timed = false;
float m_duration;
int m_ticksPerSecond;

AssimpNodeData *m_RootNode;
AssimpNodeData *m_rootNode;
std::map<std::string, AssimpNodeData *> m_assimpNodes;

std::unordered_map<std::string, Bone *> m_bones;
std::map<std::string, BoneInfo> m_BoneInfoMap;
std::map<std::string, BoneInfo> m_boneInfoMap;
std::unordered_map<std::string, float> m_blendMask;

Animation(const std::string &animationName, Model *model, bool timed = false);
Animation(const std::string &animationName, Model *model);
~Animation();
Bone *getBone(const std::string &name);
void readBones(const aiAnimation *animation, Model &model);
Expand Down
96 changes: 65 additions & 31 deletions src/animation/animator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
#include "animator.h"

Animator::Animator(std::vector<Animation *> animations)
: m_animations(animations)
{
m_animations = animations;
for (int i = 0; i < m_animations.size(); i++)
m_timers.push_back(0.0f);

// TODO: initial state

// TODO: better way?
Expand All @@ -23,24 +20,24 @@ Animator::Animator(std::vector<Animation *> animations)

Animator::~Animator()
{
// TODO: destruction
for (int i = 0; i < m_state.animations.size(); i++)
delete m_state.animations[i];
m_state.animations.clear();

for (int i = 0; i < m_state.poses.size(); i++)
delete m_state.poses[i];
m_state.poses.clear();
}

// TODO: move validations to setters
void Animator::update(float deltaTime)
{
for (int i = 0; i < m_animations.size(); i++)
{
m_timers[i] += m_animations[i]->m_TicksPerSecond * m_animations[i]->m_playbackSpeed * deltaTime;

float clampedTime = fmod(m_timers[i], m_animations[i]->m_Duration);
if (clampedTime < m_timers[i])
clampedTime += m_startOffset;
for (int i = 0; i < m_state.animations.size(); i++)
m_state.animations[i]->updateTimer(deltaTime, m_startOffset);

m_timers[i] = clampedTime;
}
for (int i = 0; i < m_state.poses.size(); i++)
m_state.poses[i]->updateTimer(deltaTime, m_startOffset);

calculateBoneTransform(m_animations[0]->m_RootNode, glm::mat4(1.0f));
calculateBoneTransform(m_animations[0]->m_rootNode, glm::mat4(1.0f));
}

void Animator::calculateBoneTransform(const AssimpNodeData *node, glm::mat4 parentTransform)
Expand All @@ -56,18 +53,18 @@ void Animator::calculateBoneTransform(const AssimpNodeData *node, glm::mat4 pare
float totalWeight = 0.0f;
for (int i = 0; i < m_state.animations.size(); i++)
{
Anim anim = m_state.animations[i];
Bone *bone = m_animations[anim.index]->getBone(nodeName);
Anim *anim = m_state.animations[i];
Bone *bone = anim->m_animation->getBone(nodeName);

if (!bone)
continue;

float blendWeight = anim.blendFactor * bone->m_blendFactor;
float blendWeight = anim->m_blendFactor * bone->m_blendFactor;

if (blendWeight == 0.0f)
continue;

bone->update(m_timers[anim.index]);
bone->update(anim->m_timer);

totalWeight += blendWeight;

Expand All @@ -92,25 +89,22 @@ void Animator::calculateBoneTransform(const AssimpNodeData *node, glm::mat4 pare
boneProcessed = true;
}

// AnimPose influence
// pose influence
for (int i = 0; i < m_state.poses.size(); i++)
{
AnimPose animPose = m_state.poses[i];
Animation *animation = m_animations[animPose.index];
Anim *anim = m_state.poses[i];
Animation *animation = anim->m_animation;
Bone *bone = animation->getBone(nodeName);

if (!bone)
continue;

float blendWeight = animPose.blendFactor * bone->m_blendFactor;
float blendWeight = anim->m_blendFactor * bone->m_blendFactor;

if (blendWeight == 0.0f)
continue;

if (animation->m_timed)
bone->update(animPose.time);
else
bone->update(m_timers[animPose.index]);
bone->update(anim->m_timer);

blendedT = glm::mix(blendedT, bone->m_translation, blendWeight);
blendedR = glm::slerp(blendedR, bone->m_rotation, blendWeight);
Expand All @@ -127,7 +121,7 @@ void Animator::calculateBoneTransform(const AssimpNodeData *node, glm::mat4 pare
glm::mat4 globalTransformation = parentTransform * nodeTransform;

// TODO: always first index is correct?
auto boneInfoMap = m_animations[0]->m_BoneInfoMap;
auto boneInfoMap = m_animations[0]->m_boneInfoMap;
if (boneInfoMap.find(nodeName) != boneInfoMap.end())
{
int index = boneInfoMap[nodeName].id;
Expand All @@ -140,7 +134,47 @@ void Animator::calculateBoneTransform(const AssimpNodeData *node, glm::mat4 pare
calculateBoneTransform(node->children[i], globalTransformation);
}

void Animator::setAnimTime(int animIndex, float time)
Anim *Animator::addStateAnimation(Animation *animation)
{
Anim *anim = new Anim(animation);
m_state.animations.push_back(anim);

return anim;
}

Anim *Animator::addPoseAnimation(Animation *animation)
{
m_timers[animIndex] = time;
Anim *anim = new Anim(animation);
m_state.poses.push_back(anim);

return anim;
}

// Anim

Anim::Anim(Animation *animation)
: m_animation(animation),
m_blendFactor(0.f),
m_playbackSpeed(1.f),
m_timerActive(true),
m_timer(0.f)
{
}

void Anim::updateTimer(float deltaTime, float startOffset)
{
if (!m_timerActive)
return;

// TODO: ?
// if (m_blendFactor == 0.f)
// return;

m_timer += m_animation->m_ticksPerSecond * m_playbackSpeed * deltaTime;

float clampedTime = fmod(m_timer, m_animation->m_duration);
if (clampedTime < m_timer)
clampedTime += startOffset;

m_timer = clampedTime;
}
27 changes: 14 additions & 13 deletions src/animation/animator.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,24 @@

#define MAX_BONES 200

struct Anim
class Anim
{
int index;
float blendFactor;
};
public:
Anim(Animation *animation);

struct AnimPose
{
int index;
float blendFactor;
float time = 0.f;
Animation *m_animation;
float m_blendFactor;
float m_playbackSpeed;
bool m_timerActive;
float m_timer;

void updateTimer(float deltaTime, float startOffset);
};

struct AnimatorState
{
std::vector<Anim> animations;
std::vector<AnimPose> poses;
std::vector<Anim *> animations;
std::vector<Anim *> poses;
};

class Animator
Expand All @@ -38,15 +39,15 @@ class Animator
std::vector<glm::mat4> m_finalBoneMatrices;
std::vector<glm::mat4> m_globalMatrices;
std::vector<Animation *> m_animations;
std::vector<float> m_timers;
AnimatorState m_state;
float m_startOffset = 0.f;

Animator(std::vector<Animation *> animations);
~Animator();
void update(float deltaTime);
void calculateBoneTransform(const AssimpNodeData *node, glm::mat4 parentTransform);
void setAnimTime(int animIndex, float time);
Anim *addStateAnimation(Animation *animation);
Anim *addPoseAnimation(Animation *animation);
};

#endif /* animator_hpp */
48 changes: 25 additions & 23 deletions src/ui/animation/animation_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

AnimationUI::AnimationUI(Animator *animator)
: m_animator(animator),
m_selectedAnimPose(0)
m_selectedAnimation(nullptr)
{
}

Expand All @@ -11,54 +11,56 @@ void AnimationUI::render()
if (!ImGui::CollapsingHeader("Animation", ImGuiTreeNodeFlags_NoTreePushOnOpen))
return;

renderBlendTable();
renderSelectedAnimPose();
renderBlendTable("State Anims", m_animator->m_state.animations);
renderBlendTable("Pose Anims", m_animator->m_state.poses);
renderSelectedAnimation();
}

void AnimationUI::renderBlendTable()
void AnimationUI::renderBlendTable(const std::string &tableName, std::vector<Anim *> &anims)
{
if (!ImGui::TreeNode("Blend Table##AnimationUI::renderBlendTable"))
if (!ImGui::TreeNode((tableName + " Blend Table##AnimationUI::renderBlendTable").c_str()))
return;

ImGui::BeginTable("AnimationTable", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders);
ImGui::BeginTable("State Animations", 5, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders);
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Blend Factor");
ImGui::TableSetupColumn("Timer");
ImGui::TableSetupColumn("Timer Active");
ImGui::TableSetupColumn("Playback Speed");
ImGui::TableHeadersRow();
for (int i = 0; i < m_animator->m_state.animations.size(); i++)
for (int i = 0; i < anims.size(); i++)
{
// int max = m_animator->m_animations.size() - 1;
// ImGui::DragInt("index", &m_animator->m_state.animations[i].index, 1, 0, max);
// ImGui::DragFloat("blendFactor", &m_animator->m_state.animations[i].blendFactor, 0.01f, 0.0f, 1.0f);
Anim *anim = anims[i];
Animation *animation = anim->m_animation;

ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
int index = m_animator->m_state.animations[i].index;
ImGui::Text("%s", m_animator->m_animations[index]->m_name.c_str());
ImGui::Text("%s", animation->m_name.c_str());
ImGui::TableSetColumnIndex(1);
ImGui::Text("%.3f", m_animator->m_state.animations[i].blendFactor);
ImGui::DragFloat(("##m_blendFactor:" + animation->m_name).c_str(), &anim->m_blendFactor, 0.01f, 0.0f);
ImGui::TableSetColumnIndex(2);
ImGui::DragFloat(("##m_playbackSpeed:" + m_animator->m_animations[i]->m_name).c_str(), &m_animator->m_animations[i]->m_playbackSpeed, 0.01f, 0.0f);
ImGui::DragFloat(("##m_timer:" + animation->m_name).c_str(), &anim->m_timer, 1.f);
ImGui::TableSetColumnIndex(3);
ImGui::Checkbox(("##m_timerActive:" + animation->m_name).c_str(), &anim->m_timerActive);
ImGui::TableSetColumnIndex(4);
ImGui::DragFloat(("##m_playbackSpeed:" + animation->m_name).c_str(), &anim->m_playbackSpeed, 0.01f, 0.0f);
}
ImGui::EndTable();

ImGui::TreePop();
}

void AnimationUI::renderSelectedAnimPose()
void AnimationUI::renderSelectedAnimation()
{
ImGui::DragInt("AnimPose Index##AnimationUI::renderSelectedAnimPose", &m_selectedAnimPose, 1, 0, m_animator->m_state.poses.size() - 1);

if (m_animator->m_state.poses.empty())
if (m_selectedAnimation == nullptr)
return;

AnimPose *animPose = &m_animator->m_state.poses[m_selectedAnimPose];
ImGui::Text("Name: %s, Index: %d", m_animator->m_animations[animPose->index]->m_name.c_str(), animPose->index);
ImGui::DragFloat("Blend Factor##AnimationUI::renderSelectedAnimPose", &animPose->blendFactor, 0.01f, 0.0f, 1.0f);
ImGui::Text("Name: %s", m_selectedAnimation->m_name.c_str());

if (!ImGui::TreeNode("Selected AnimPose##AnimationUI::renderSelectedAnimPose"))
if (!ImGui::TreeNode("Bones##AnimationUI::renderSelectedAnimation"))
return;

auto bonesMap = &m_animator->m_animations[animPose->index]->m_bones;
auto bonesMap = &m_selectedAnimation->m_bones;
for (auto it = bonesMap->begin(); it != bonesMap->end(); ++it)
{
Bone *bone = it->second;
Expand Down
6 changes: 3 additions & 3 deletions src/ui/animation/animation_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class AnimationUI : public BaseUI
public:
AnimationUI(Animator *animator);

int m_selectedAnimPose;
Animation *m_selectedAnimation;

void render() override;

void renderBlendTable();
void renderSelectedAnimPose();
void renderBlendTable(const std::string &tableName, std::vector<Anim *> &anims);
void renderSelectedAnimation();
};

#endif /* animation_ui_hpp */

0 comments on commit c6318dc

Please sign in to comment.