Modified SHAnimationComponent to handle interpolation of separate position, rotation and scale keyframes

This commit is contained in:
Kah Wei 2023-01-09 23:32:20 +08:00
parent 7bf0c26052
commit e9624977cd
4 changed files with 73 additions and 24 deletions

View File

@ -20,8 +20,8 @@ namespace SHADE
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset) SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset)
: ticksPerSecond { asset.ticksPerSecond } : ticksPerSecond { static_cast<int>(asset.ticksPerSecond) }
, totalTime { asset.duration } , totalTime { static_cast<float>(asset.duration) }
{ {
// Populate keyframes // Populate keyframes
for (const auto& channel : asset.nodeChannels) for (const auto& channel : asset.nodeChannels)
@ -47,6 +47,8 @@ namespace SHADE
newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ static_cast<int>(scaleKey.time), scaleKey.value}); newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ static_cast<int>(scaleKey.time), scaleKey.value});
} }
newChannel.MaxFrames = std::max({ newChannel.PositionKeyFrames.size(), newChannel.RotationKeyFrames.size(), newChannel.ScaleKeyFrames.size() });
// Insert the channel // Insert the channel
channels.emplace_back(std::move(newChannel)); channels.emplace_back(std::move(newChannel));
} }

View File

@ -51,6 +51,7 @@ namespace SHADE
std::vector<SHAnimationKeyFrame<SHVec3>> PositionKeyFrames; std::vector<SHAnimationKeyFrame<SHVec3>> PositionKeyFrames;
std::vector<SHAnimationKeyFrame<SHQuaternion>> RotationKeyFrames; std::vector<SHAnimationKeyFrame<SHQuaternion>> RotationKeyFrames;
std::vector<SHAnimationKeyFrame<SHVec3>> ScaleKeyFrames; std::vector<SHAnimationKeyFrame<SHVec3>> ScaleKeyFrames;
int MaxFrames;
}; };
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -83,6 +83,7 @@ namespace SHADE
return; return;
currClip = newClip; currClip = newClip;
secsPerTick = 1.0f / currClip->GetTicksPerSecond();
updatePoseWithClip(0.0f); updatePoseWithClip(0.0f);
} }
@ -135,36 +136,74 @@ namespace SHADE
bones.push(child); bones.push(child);
} }
// Get interpolated frame // Get closest frame index
auto firstKeyFrame = channel.KeyFrames.end(); const int CLOSEST_FRAME_IDX = static_cast<int>(std::floorf(poseTime * currClip->GetTicksPerSecond()));
auto nextKeyFrame = channel.KeyFrames.end();
for (auto iter = channel.KeyFrames.begin(); iter != channel.KeyFrames.end(); ++iter) // Calculate the matrix from interpolated values
{
const auto& KEYFRAME = *iter;
if(KEYFRAME.TimeStamp <= poseTime)
{
firstKeyFrame = iter;
}
else if (KEYFRAME.TimeStamp > poseTime)
{
nextKeyFrame = iter;
break;
}
}
// Calculate the matrix
const int BONE_MTX_IDX = rig->GetNodeIndex(bone); const int BONE_MTX_IDX = rig->GetNodeIndex(bone);
const float T = (poseTime - firstKeyFrame->TimeStamp) / (nextKeyFrame->TimeStamp - firstKeyFrame->TimeStamp);
boneMatrices[BONE_MTX_IDX] = boneMatrices[BONE_MTX_IDX] * SHMatrix::Transform boneMatrices[BONE_MTX_IDX] = boneMatrices[BONE_MTX_IDX] * SHMatrix::Transform
( (
SHVec3::Lerp(firstKeyFrame->Position, nextKeyFrame->Position, T), getInterpolatedValue(channel.PositionKeyFrames, CLOSEST_FRAME_IDX, poseTime),
SHQuaternion::Slerp(firstKeyFrame->Orientation, nextKeyFrame->Orientation, T), getInterpolatedValue(channel.RotationKeyFrames, CLOSEST_FRAME_IDX, poseTime),
SHVec3::Lerp(firstKeyFrame->Scale, nextKeyFrame->Scale, T) getInterpolatedValue(channel.ScaleKeyFrames, CLOSEST_FRAME_IDX, poseTime)
); );
} }
} }
} }
SHVec3 SHAnimatorComponent::getInterpolatedValue(const std::vector<SHAnimationKeyFrame<SHVec3>>& keyframes, int closestFrameIndex, float poseTime)
{
// Find the key frames that surround the current frame index
auto firstKeyFrame = keyframes.end();
auto nextKeyFrame = keyframes.end();
for (auto iter = keyframes.begin(); iter != keyframes.end(); ++iter)
{
const auto& KEYFRAME = *iter;
if (KEYFRAME.FrameIndex <= closestFrameIndex)
{
firstKeyFrame = iter;
}
else if (KEYFRAME.FrameIndex > closestFrameIndex)
{
nextKeyFrame = iter;
break;
}
}
// Get interpolated vector
const float PREV_FRAME_TIME = firstKeyFrame->FrameIndex * secsPerTick;
const float NEXT_FRAME_TIME = nextKeyFrame->FrameIndex * secsPerTick;
const float T = (poseTime - PREV_FRAME_TIME) / (NEXT_FRAME_TIME - PREV_FRAME_TIME);
return SHVec3::Lerp(firstKeyFrame->Data, nextKeyFrame->Data, T);
}
SHQuaternion SHAnimatorComponent::getInterpolatedValue(const std::vector<SHAnimationKeyFrame<SHQuaternion>>& keyframes, int closestFrameIndex, float poseTime)
{
// Find the key frames that surround the current frame index
auto firstKeyFrame = keyframes.end();
auto nextKeyFrame = keyframes.end();
for (auto iter = keyframes.begin(); iter != keyframes.end(); ++iter)
{
const auto& KEYFRAME = *iter;
if (KEYFRAME.FrameIndex <= closestFrameIndex)
{
firstKeyFrame = iter;
}
else if (KEYFRAME.FrameIndex > closestFrameIndex)
{
nextKeyFrame = iter;
break;
}
}
// Get interpolated vector
const float PREV_FRAME_TIME = firstKeyFrame->FrameIndex * secsPerTick;
const float NEXT_FRAME_TIME = nextKeyFrame->FrameIndex * secsPerTick;
const float T = (poseTime - PREV_FRAME_TIME) / (NEXT_FRAME_TIME - PREV_FRAME_TIME);
return SHQuaternion::Slerp(firstKeyFrame->Data, nextKeyFrame->Data, T);
}
} }
/*-------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------*/

View File

@ -19,6 +19,9 @@ of DigiPen Institute of Technology is prohibited.
#include "ECS_Base/Components/SHComponent.h" #include "ECS_Base/Components/SHComponent.h"
#include "Resource/SHHandle.h" #include "Resource/SHHandle.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
#include "SHAnimationClip.h"
namespace SHADE namespace SHADE
{ {
@ -119,6 +122,8 @@ namespace SHADE
// Playback Tracking // Playback Tracking
float currPlaybackTime = 0.0f; float currPlaybackTime = 0.0f;
bool isPlaying = false; bool isPlaying = false;
// Useful Cached Data
float secsPerTick = 0.0f;
// Buffer // Buffer
std::vector<SHMatrix> boneMatrices; std::vector<SHMatrix> boneMatrices;
@ -126,6 +131,8 @@ namespace SHADE
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void updatePoseWithClip(float poseTime); void updatePoseWithClip(float poseTime);
SHVec3 getInterpolatedValue(const std::vector<SHAnimationKeyFrame<SHVec3>>& keyframes, int closestFrameIndex, float poseTime);
SHQuaternion getInterpolatedValue(const std::vector<SHAnimationKeyFrame<SHQuaternion>>& keyframes, int closestFrameIndex, float poseTime);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* RTTR */ /* RTTR */