From c1910db2af0a6022a2670f691a31c0a4f5f9b6ca Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 3 Jan 2023 00:23:37 +0800 Subject: [PATCH] Fleshed out SHAnimatorComponent --- .../src/Animation/SHAnimationClip.cpp | 4 + SHADE_Engine/src/Animation/SHAnimationClip.h | 22 ++- .../src/Animation/SHAnimatorComponent.cpp | 132 +++++++++++++++++- .../src/Animation/SHAnimatorComponent.h | 58 +++++++- SHADE_Engine/src/Animation/SHRig.cpp | 12 ++ SHADE_Engine/src/Animation/SHRig.h | 7 + .../src/Graphics/MiddleEnd/Batching/SHBatch.h | 1 + 7 files changed, 220 insertions(+), 16 deletions(-) diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.cpp b/SHADE_Engine/src/Animation/SHAnimationClip.cpp index 1f199b3f..4ef91a39 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationClip.cpp @@ -19,6 +19,10 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------------*/ + SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset) + { + + } /*-----------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.h b/SHADE_Engine/src/Animation/SHAnimationClip.h index ed1b7b81..d8415942 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.h +++ b/SHADE_Engine/src/Animation/SHAnimationClip.h @@ -19,15 +19,12 @@ of DigiPen Institute of Technology is prohibited. namespace SHADE { - /*-----------------------------------------------------------------------------------*/ - /* Forward Declarations */ - /*-----------------------------------------------------------------------------------*/ - - /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - + /// + /// Defines a single key frame in an animation. + /// struct SHAnimationKeyFrame { float TimeStamp; @@ -37,11 +34,19 @@ namespace SHADE SHMatrix TransformationMatrix; }; + /// + /// Represents a animation clip of a 3D animation that is made for a specific model + /// rig. + /// class SHAnimationClip { + public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ + /// + /// Defines the animations of a single bone in a rig. + /// struct Channel { std::string Name; @@ -56,12 +61,15 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + const std::vector& GetChannels() const noexcept { return channels; } + float GetTotalTime() const noexcept { return totalTime; } private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ - std::vector Channels; + std::vector channels; + float totalTime; /*---------------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp index debb2fb2..629453a6 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp @@ -13,12 +13,50 @@ of DigiPen Institute of Technology is prohibited. #include "SHpch.h" // Primary Include #include "SHAnimatorComponent.h" +// STL Includes +#include // Project Includes #include "SHRig.h" #include "Math/SHMatrix.h" +#include "SHAnimationClip.h" +#include "Graphics/SHVkUtil.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include "ECS_Base/Managers/SHSystemManager.h" namespace SHADE { + /*-----------------------------------------------------------------------------------*/ + /* Usage Functions */ + /*-----------------------------------------------------------------------------------*/ + void SHAnimatorComponent::Play() + { + isPlaying = false; + } + + void SHAnimatorComponent::Play(Handle clip) + { + currClip = clip; + currPlaybackTime = 0.0f; + Play(); + } + + void SHAnimatorComponent::PlayFromStart() + { + isPlaying = true; + currPlaybackTime = 0.0f; + } + + void SHAnimatorComponent::Pause() + { + isPlaying = false; + } + + void SHAnimatorComponent::Stop() + { + isPlaying = false; + currPlaybackTime = 0.0f; + } + /*-----------------------------------------------------------------------------------*/ /* Setter Functions */ /*-----------------------------------------------------------------------------------*/ @@ -31,14 +69,21 @@ namespace SHADE rig = newRig; // Populate bone matrices based on new rig's default pose + boneMatrices.clear(); if (rig) { + std::fill_n(std::back_inserter(boneMatrices), rig->GetNodeCount(), SHMatrix::Identity); + } + } - } - else - { - boneMatrices.clear(); - } + void SHAnimatorComponent::SetClip(Handle newClip) + { + // No change + if (currClip == newClip) + return; + + currClip = newClip; + updatePoseWithClip(0.0f); } /*-----------------------------------------------------------------------------------*/ @@ -46,10 +91,85 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ void SHAnimatorComponent::Update(float dt) { - // Set everything to identity + // Nothing to animate + if (!currClip || !isPlaying) + return; + + // Update time on the playback + currPlaybackTime += dt; + if (currPlaybackTime > currClip->GetTotalTime()) + { + currPlaybackTime = currPlaybackTime - currClip->GetTotalTime(); + } + + // Reset all matrices + for (auto& mat : boneMatrices) + { + mat = SHMatrix::Identity; + } + + // Play the clip + updatePoseWithClip(currPlaybackTime); } + + /*-----------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------------*/ + void SHAnimatorComponent::updatePoseWithClip(float poseTime) + { + for (const auto& channel : currClip->GetChannels()) + { + // Get the bone + std::queue> bones; + bones.push(rig->GetNode(channel.Name)); + while (!bones.empty()) + { + // Select bone at front of the queue + auto bone = bones.front(); bones.pop(); + if (!bone) + continue; + + // Add any children to the queue + for (auto child : bone->Children) + { + 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 + 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) + ); + } + } + } + } +/*-------------------------------------------------------------------------------------*/ +/* RTTR Registration */ +/*-------------------------------------------------------------------------------------*/ RTTR_REGISTRATION { using namespace SHADE; diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.h b/SHADE_Engine/src/Animation/SHAnimatorComponent.h index 446014cc..056aa536 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.h +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.h @@ -26,6 +26,8 @@ namespace SHADE /* Forward Declarations */ /*-----------------------------------------------------------------------------------*/ class SHRig; + class SHAnimationClip; + class SHVkBuffer; /*-----------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -40,20 +42,61 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Usage Functions */ /*---------------------------------------------------------------------------------*/ - /*void Play(); + /// + /// Plays the currently loaded animation from the last time. + /// + void Play(); + /// + /// Plays the specified animation clip from the start. + /// + /// + void Play(Handle clip); + /// + /// Plays the currently loaded animation clip from the start. + /// void PlayFromStart(); + /// + /// Pauses the animation at the current time. + /// void Pause(); - void Stop();*/ + /// + /// Stops the animation and resets the play time back to 0. + /// + void Stop(); /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ + /// + /// Sets the animation rig for this animator. + /// + /// Rig to use. void SetRig(Handle newRig); + /// + /// Sets the animation clip of this animator without playing it. + /// This will set the pose of the model to it's initial pose. + /// If the clip is the same as the current clip, nothing happens. + /// + /// Clip to use. + void SetClip(Handle newClip); /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ + /// + /// Retrieves all the bone matrices of this animator. + /// + /// Reference to a vector of the bone matrices. const std::vector& GetBoneMatrices() const noexcept { return boneMatrices; } + /// + /// Retrieve the currently set animation clip. + /// + /// Handle to the currently set animation clip. + Handle GetCurrentClip() const noexcept { return currClip; } + /// + /// Checks if an animation is currently playing. + /// + /// True if an animation clip is currently playing. bool IsPlaying() const { return isPlaying; } /*---------------------------------------------------------------------------------*/ @@ -70,10 +113,19 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ + // Resources Handle rig; - std::vector boneMatrices; + Handle currClip; + // Playback Tracking float currPlaybackTime = 0.0f; bool isPlaying = false; + // Buffer + std::vector boneMatrices; + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void updatePoseWithClip(float poseTime); /*---------------------------------------------------------------------------------*/ /* RTTR */ diff --git a/SHADE_Engine/src/Animation/SHRig.cpp b/SHADE_Engine/src/Animation/SHRig.cpp index 2214baa5..7c3059de 100644 --- a/SHADE_Engine/src/Animation/SHRig.cpp +++ b/SHADE_Engine/src/Animation/SHRig.cpp @@ -60,6 +60,16 @@ namespace SHADE return nodeCount; } + int SHRig::GetNodeIndex(Handle node) const noexcept + { + if (nodeIndexMap.contains(node)) + { + return nodeIndexMap.at(node); + } + + return -1; + } + /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ @@ -78,6 +88,8 @@ namespace SHADE { nodeNames.emplace(newNode, NODE_DATA.name); nodesByName.emplace(NODE_DATA.name, newNode); + nodeIndexMap.emplace(newNode, nodes.size()); + nodes.emplace_back(newNode); } // Fill child nodes diff --git a/SHADE_Engine/src/Animation/SHRig.h b/SHADE_Engine/src/Animation/SHRig.h index af1b79ec..5c4f720d 100644 --- a/SHADE_Engine/src/Animation/SHRig.h +++ b/SHADE_Engine/src/Animation/SHRig.h @@ -34,6 +34,7 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ class SHRig { + public: /*---------------------------------------------------------------------------------*/ /* Type Definitions */ /*---------------------------------------------------------------------------------*/ @@ -78,6 +79,10 @@ namespace SHADE /// needed. /// int GetNodeCount() const noexcept; + /// + /// Retrieves the index in the node storage. + /// + int GetNodeIndex(Handle node) const noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -86,6 +91,8 @@ namespace SHADE Handle rootNode; std::unordered_map, std::string> nodeNames; std::unordered_map> nodesByName; + std::vector> nodes; + std::unordered_map, int> nodeIndexMap; int nodeCount = 0; SHResourceLibrary nodeStore; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index 08f07ea6..477a5720 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -134,6 +134,7 @@ namespace SHADE TripleDescSet matPropsDescSet; TripleBuffer boneMatrixBuffer; TripleBuffer boneFirstIndexBuffer; + TripleDescSet boneMatricesDescSet; /*-----------------------------------------------------------------------------*/ /* Helper Functions */