Skip to content

Commit

Permalink
Implement animation code
Browse files Browse the repository at this point in the history
  • Loading branch information
vadimvinokurov committed Sep 3, 2022
1 parent 2d6dbc2 commit 4602013
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 82 deletions.
49 changes: 15 additions & 34 deletions Sources/AnimTrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,31 @@
#include <sstream>
#include "AnimFrame.h"
#include "Math/MathUtils.h"
#include <algorithm>

template <typename T>
class AnimTrack
{
public:
AnimTrack(std::vector<AnimFrame<T>> frames);
void setFrames(const std::vector<AnimFrame<T>>& frames);
T sample(float time, bool looping) const;
uint32 frameIndex(float time, bool looping) const;
float adjustTimeToFitTrack(float time, bool looping) const;
float getStartTime() const;
float getEndTime() const;
bool empty() const;

private:
T normalize_if_quaternion(const T &value) const;

std::vector<AnimFrame<T>> frames_;
};

template <typename T>
AnimTrack<T>::AnimTrack(std::vector<AnimFrame<T>> frames) : frames_(std::move(frames))
{
}

template <typename T>
T AnimTrack<T>::sample(float time, bool looping) const
{
if (frames_.empty())
if (empty())
{
return T();
}
if (frames_.size() == 1)
{
return frames_.front().value;
}
float itime = time;
time = adjustTimeToFitTrack(time, looping);
uint32 thisFrame = frameIndex(time, looping);
Expand Down Expand Up @@ -74,16 +65,13 @@ float AnimTrack<T>::adjustTimeToFitTrack(float time, bool looping) const
template <typename T>
uint32 AnimTrack<T>::frameIndex(float time, bool looping) const
{
if (!looping)
if (time <= frames_.front().time)
{
if (time <= frames_.front().time)
{
return 0;
}
if (time >= frames_.back().time)
{
return frames_.size() - 1;
}
return 0;
}
if (time >= frames_.back().time)
{
return frames_.size() - 1;
}

for (uint32 i = frames_.size() - 1; i >= 0; --i)
Expand All @@ -108,23 +96,16 @@ T AnimTrack<T>::normalize_if_quaternion(const T &value) const
return value;
}
}

template <typename T>
float AnimTrack<T>::getStartTime() const
bool AnimTrack<T>::empty() const
{
if (frames_.empty())
{
return 0.0f;
}
return frames_.front().time;
return frames_.size() < 2;
}
template <typename T>
float AnimTrack<T>::getEndTime() const
void AnimTrack<T>::setFrames(const std::vector<AnimFrame<T>> &frames)
{
if (frames_.empty())
{
return 0.0f;
}
return frames_.back().time;
frames_ = frames;
}

#endif // VENGINE3D_ANIMTRACK_H
38 changes: 38 additions & 0 deletions Sources/AnimTransformTrack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,41 @@
//

#include "AnimTransformTrack.h"
void AnimTransformTrack::setPositionTrack(const AnimTrack<Vector3> &position)
{
position_ = position;
}

void AnimTransformTrack::setRotationTrack(const AnimTrack<Quaternion> &rotation)
{
rotation_ = rotation;
}

void AnimTransformTrack::setScalingTrack(const AnimTrack<Vector3> &scale)
{
scale_ = scale;
}

void AnimTransformTrack::setBoneId(int32 boneId)
{
boneId_ = boneId;
}
int32 AnimTransformTrack::getBoneId() const
{
return boneId_;
}
void AnimTransformTrack::sample(Transform &transform, float time, bool looping) const
{
if (!position_.empty())
{
transform.position = position_.sample(time, looping);
}
if (!rotation_.empty())
{
transform.rotation = rotation_.sample(time, looping);
}
if (!scale_.empty())
{
transform.scale = scale_.sample(time, looping);
}
}
14 changes: 14 additions & 0 deletions Sources/AnimTransformTrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,23 @@
#define VENGINE3D_ANIMTRANSFORMTRACK_H

#include "AnimTrack.h"
#include "Bone.h"

class AnimTransformTrack
{
public:
void setPositionTrack(const AnimTrack<Vector3>& position);
void setRotationTrack(const AnimTrack<Quaternion>& rotation);
void setScalingTrack(const AnimTrack<Vector3>& scale);
void setBoneId(int32 boneId);
int32 getBoneId() const;
void sample(Transform &transform, float time, bool looping) const;

private:
AnimTrack<Vector3> position_;
AnimTrack<Quaternion> rotation_;
AnimTrack<Vector3> scale_;
int32 boneId_;
};

#endif // VENGINE3D_ANIMTRANSFORMTRACK_H
41 changes: 41 additions & 0 deletions Sources/Animation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Created by boris on 9/3/2022.
//

#include <algorithm>
#include "Animation.h"

void Animation::addTransformTrack(const AnimTransformTrack &transformTrack)
{
transformTracks_.push_back(transformTrack);
}

void Animation::setLooping(bool looping)
{
looping_ = looping;
}

void Animation::setDuration(float durationInSeconds)
{
durationInSeconds_ = durationInSeconds;
}

float Animation::sample(Skeleton &skeleton, float time) const
{
time = adjustTimeToFitAnimation(time);

for (const auto &transformTrack : transformTracks_)
{
transformTrack.sample(skeleton[transformTrack.getBoneId()], time, looping_);
}
return time;
}

float Animation::adjustTimeToFitAnimation(float time) const
{
return looping_ ? VEMath::loopclamp(time, 0.0f, durationInSeconds_) : std::clamp(time, 0.0f, durationInSeconds_);
}
void Animation::setName(const std::string &name)
{
name_ = name;
}
28 changes: 28 additions & 0 deletions Sources/Animation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Created by boris on 9/3/2022.
//

#ifndef VENGINE3D_ANIMATION_H
#define VENGINE3D_ANIMATION_H

#include "AnimTransformTrack.h"
#include "Skeleton.h"

class Animation
{
public:
void setName(const std::string& name);
void addTransformTrack(const AnimTransformTrack &transformTrack);
void setLooping(bool looping);
float sample(Skeleton &skeleton, float time) const;
void setDuration(float durationInSeconds);

private:
float adjustTimeToFitAnimation(float time) const;
std::vector<AnimTransformTrack> transformTracks_;
std::string name_;
bool looping_ = false;
float durationInSeconds_ = 0;
};

#endif // VENGINE3D_ANIMATION_H
40 changes: 22 additions & 18 deletions Sources/AssetImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ void AssetImporter::loadBones(std::vector<Bone> &bones, aiNode *node, int32 pare
int32 boneId = boneIndexMap[std::string(node->mName.C_Str())];
bones[boneId].transform = getTransform(node->mTransformation);
bones[boneId].parentId = parentId;
bones[boneId].name = node->mName.C_Str();

for (uint32 i = 0; i < node->mNumChildren; ++i)
{
Expand Down Expand Up @@ -202,37 +203,41 @@ std::vector<StaticMesh> AssetImporter::loadMeshes()
}
return meshes;
}
void AssetImporter::getAnimations()
std::unordered_map<std::string, Animation> AssetImporter::getAnimations()
{
spdlog::warn("Anim number: {}", pScene->mNumAnimations);
std::unordered_map<std::string, Animation> animations;

tcb::span<aiAnimation *> animations(pScene->mAnimations, pScene->mNumAnimations);
for (const auto &anim : animations)
tcb::span<aiAnimation *> animationsSrc(pScene->mAnimations, pScene->mNumAnimations);
for (const auto &anim : animationsSrc)
{
loadAnimation(anim);
return;
animations.emplace(anim->mName.C_Str(), loadAnimation(anim));
}
return animations;
}

void AssetImporter::loadAnimation(const aiAnimation *animation)
Animation AssetImporter::loadAnimation(const aiAnimation *animationSrc)
{
spdlog::warn("Anim: {}; Duration: {}, tickPerSec: {}", animation->mName.C_Str(), animation->mDuration,
animation->mTicksPerSecond);
tcb::span<aiNodeAnim *> channels(animation->mChannels, animation->mNumChannels);
float durationInSec = animationSrc->mDuration / animationSrc->mTicksPerSecond;
Animation animation;
animation.setName(animationSrc->mName.C_Str());
animation.setDuration(durationInSec);

tcb::span<aiNodeAnim *> channels(animationSrc->mChannels, animationSrc->mNumChannels);
for (const auto &channel : channels)
{
loadChannel(channel, animation->mTicksPerSecond);
return;
animation.addTransformTrack(loadChannel(channel, animationSrc->mTicksPerSecond));
}
return animation;
}

AnimTransformTrack AssetImporter::loadChannel(const aiNodeAnim *channel, float tickPerSecond)
{
auto positionTrack = loadTrack(channel->mPositionKeys, channel->mNumPositionKeys, tickPerSecond);
auto scalingTrack = loadTrack(channel->mScalingKeys, channel->mNumScalingKeys, tickPerSecond);
auto rotationTrack = loadTrack(channel->mRotationKeys, channel->mNumRotationKeys, tickPerSecond);

return AnimTransformTrack();
AnimTransformTrack transformTrack;
transformTrack.setPositionTrack(loadTrack(channel->mPositionKeys, channel->mNumPositionKeys, tickPerSecond));
transformTrack.setRotationTrack(loadTrack(channel->mRotationKeys, channel->mNumRotationKeys, tickPerSecond));
transformTrack.setScalingTrack(loadTrack(channel->mScalingKeys, channel->mNumScalingKeys, tickPerSecond));
transformTrack.setBoneId(boneIndexMap[channel->mNodeName.C_Str()]);
return transformTrack;
}

AnimFrame<Vector3> AssetImporter::toAnimFrame(const aiVectorKey &key, float tickPerSecond)
Expand All @@ -250,4 +255,3 @@ AnimFrame<Quaternion> AssetImporter::toAnimFrame(const aiQuatKey &key, float tic
frame.value = Quaternion(key.mValue.x, key.mValue.y, key.mValue.z, key.mValue.w);
return frame;
}

16 changes: 7 additions & 9 deletions Sources/AssetImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,8 @@
#include "span.h"
#include "AssetTypeTraits.h"

#include "Transform.h"
#include "Bone.h"
#include "Skeleton.h"
#include "StaticMesh.h"
#include "AnimTransformTrack.h"
#include "Animation.h"

using Weights = std::map<int32, float>;
using VertexWeights = std::map<uint32, Weights>;
Expand All @@ -32,7 +29,7 @@ class AssetImporter
std::vector<StaticMesh> loadMeshes();
SkeletalMeshModel getSkeletalMesh();
Skeleton getSkeleton();
void getAnimations();
std::unordered_map<std::string, Animation> getAnimations();

private:
void boneIndexing();
Expand All @@ -41,7 +38,7 @@ class AssetImporter
std::pair<IVector4, Vector4> weightsToEngineType(const Weights &weights);

void loadBones(std::vector<Bone> &bones, aiNode *node, int32 parentId);
void loadAnimation(const aiAnimation *animation);
Animation loadAnimation(const aiAnimation *animationSrc);
AnimTransformTrack loadChannel(const aiNodeAnim *channel, float tickPerSecond);

template <class T>
Expand All @@ -60,6 +57,7 @@ template <class T>
auto AssetImporter::loadTrack(const T *aiKeys, uint32 size, float tickPerSecond)
{
using EngineValueType = AssetSameType_t<decltype(aiKeys->mValue)>;
AnimTrack<EngineValueType> track;

tcb::span<const T> keysSrc(aiKeys, size);
std::vector<AnimFrame<EngineValueType>> keys;
Expand All @@ -72,12 +70,12 @@ auto AssetImporter::loadTrack(const T *aiKeys, uint32 size, float tickPerSecond)
if (keys.back().time <= lastTime)
{
assert(false && "Incorrect animation track. Frame time less then previous frame.");
keys.resize(1);
return AnimTrack(keys);
return track;
}
lastTime = keys.back().time;
}
return AnimTrack(std::move(keys));
track.setFrames(keys);
return track;
}

#endif // VENGINE3D_ASSETIMPORTER_H
1 change: 1 addition & 0 deletions Sources/Bone.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
static constexpr int32 INVALID_BODE_ID = -1;

struct Bone{
std::string name;
int32 parentId;
Transform transform;
};
Expand Down
Loading

0 comments on commit 4602013

Please sign in to comment.