diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.cpp b/SHADE_Engine/src/Animation/SHAnimationClip.cpp index a6841e0a..666c548d 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationClip.cpp @@ -20,8 +20,8 @@ namespace SHADE /* Constructors */ /*-----------------------------------------------------------------------------------*/ SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset) - : ticksPerSecond { asset.ticksPerSecond } - , totalTime { asset.duration } + : ticksPerSecond { static_cast(asset.ticksPerSecond) } + , totalTime { static_cast(asset.duration) } { // Populate keyframes for (const auto& channel : asset.nodeChannels) @@ -47,6 +47,8 @@ namespace SHADE newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame{ static_cast(scaleKey.time), scaleKey.value}); } + newChannel.MaxFrames = std::max({ newChannel.PositionKeyFrames.size(), newChannel.RotationKeyFrames.size(), newChannel.ScaleKeyFrames.size() }); + // Insert the channel channels.emplace_back(std::move(newChannel)); } diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.h b/SHADE_Engine/src/Animation/SHAnimationClip.h index 9e34256b..fa8466b8 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.h +++ b/SHADE_Engine/src/Animation/SHAnimationClip.h @@ -51,6 +51,7 @@ namespace SHADE std::vector> PositionKeyFrames; std::vector> RotationKeyFrames; std::vector> ScaleKeyFrames; + int MaxFrames; }; /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp index 629453a6..4b2ca166 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp @@ -83,6 +83,7 @@ namespace SHADE return; currClip = newClip; + secsPerTick = 1.0f / currClip->GetTicksPerSecond(); updatePoseWithClip(0.0f); } @@ -135,36 +136,74 @@ namespace SHADE bones.push(child); } - // Get interpolated frame - auto firstKeyFrame = channel.KeyFrames.end(); - auto nextKeyFrame = channel.KeyFrames.end(); - for (auto iter = channel.KeyFrames.begin(); iter != channel.KeyFrames.end(); ++iter) - { - const auto& KEYFRAME = *iter; - - if(KEYFRAME.TimeStamp <= poseTime) - { - firstKeyFrame = iter; - } - else if (KEYFRAME.TimeStamp > poseTime) - { - nextKeyFrame = iter; - break; - } - } - // Calculate the matrix + // Get closest frame index + const int CLOSEST_FRAME_IDX = static_cast(std::floorf(poseTime * currClip->GetTicksPerSecond())); + + // Calculate the matrix from interpolated values 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 ( - SHVec3::Lerp(firstKeyFrame->Position, nextKeyFrame->Position, T), - SHQuaternion::Slerp(firstKeyFrame->Orientation, nextKeyFrame->Orientation, T), - SHVec3::Lerp(firstKeyFrame->Scale, nextKeyFrame->Scale, T) + getInterpolatedValue(channel.PositionKeyFrames, CLOSEST_FRAME_IDX, poseTime), + getInterpolatedValue(channel.RotationKeyFrames, CLOSEST_FRAME_IDX, poseTime), + getInterpolatedValue(channel.ScaleKeyFrames, CLOSEST_FRAME_IDX, poseTime) ); } } } + SHVec3 SHAnimatorComponent::getInterpolatedValue(const std::vector>& 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>& 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); + } } /*-------------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.h b/SHADE_Engine/src/Animation/SHAnimatorComponent.h index 056aa536..91edc9fc 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.h +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.h @@ -19,6 +19,9 @@ of DigiPen Institute of Technology is prohibited. #include "ECS_Base/Components/SHComponent.h" #include "Resource/SHHandle.h" #include "Math/SHMatrix.h" +#include "Math/Vector/SHVec3.h" +#include "Math/SHQuaternion.h" +#include "SHAnimationClip.h" namespace SHADE { @@ -119,6 +122,8 @@ namespace SHADE // Playback Tracking float currPlaybackTime = 0.0f; bool isPlaying = false; + // Useful Cached Data + float secsPerTick = 0.0f; // Buffer std::vector boneMatrices; @@ -126,6 +131,8 @@ namespace SHADE /* Helper Functions */ /*---------------------------------------------------------------------------------*/ void updatePoseWithClip(float poseTime); + SHVec3 getInterpolatedValue(const std::vector>& keyframes, int closestFrameIndex, float poseTime); + SHQuaternion getInterpolatedValue(const std::vector>& keyframes, int closestFrameIndex, float poseTime); /*---------------------------------------------------------------------------------*/ /* RTTR */