From f844079eea4ca611e19793bdd6c214a749daa77f Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 14 Mar 2023 14:07:46 +0800 Subject: [PATCH 1/2] Added support for changing playback speed of an animation clip --- .../src/Animation/SHAnimationClip.cpp | 13 +++++---- SHADE_Engine/src/Animation/SHAnimationClip.h | 28 ++++++++++++++----- .../src/Animation/SHAnimationController.cpp | 13 +++++---- .../src/Animation/SHAnimatorComponent.cpp | 2 +- .../Asset Types/SHAnimClipContainerAsset.h | 1 + .../SHRawAnimInspector.cpp | 15 +++++++++- .../SHRawAnimInspector.h | 1 + .../src/Resource/SHResourceManager.hpp | 3 +- 8 files changed, 55 insertions(+), 21 deletions(-) diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.cpp b/SHADE_Engine/src/Animation/SHAnimationClip.cpp index 2066506f..b45701d8 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationClip.cpp @@ -20,12 +20,13 @@ namespace SHADE /*-----------------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------------*/ - SHAnimationClip::SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame) - : rawAnim { rawAnimHandle } - , startFrameIndex { firstFrame } - , endFrameIndex { lastFrame } - , duration { 0.0f } - , startTimeStamp { 0.0f } + SHAnimationClip::SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame, float playbackMultiplier) + : rawAnim { rawAnimHandle } + , startFrameIndex { firstFrame } + , endFrameIndex { lastFrame } + , duration { 0.0f } + , startTimeStamp { 0.0f } + , playbackSpeedMultiplier { playbackMultiplier } { if (!rawAnim) return; diff --git a/SHADE_Engine/src/Animation/SHAnimationClip.h b/SHADE_Engine/src/Animation/SHAnimationClip.h index 6b97c955..2c6b6561 100644 --- a/SHADE_Engine/src/Animation/SHAnimationClip.h +++ b/SHADE_Engine/src/Animation/SHAnimationClip.h @@ -41,25 +41,39 @@ namespace SHADE /// Handle to the raw animation data. /// First frame to be played. /// Last frame to be played. - SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame); + /// Multiplier for the playback speed. + SHAnimationClip(Handle rawAnimHandle, int firstFrame, int lastFrame, float playbackMultiplier = 1.0f); /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ inline Handle GetRawAnimation() const noexcept { return rawAnim; } inline int GetStartFrameIndex() const noexcept { return startFrameIndex; } - inline int GetEndFrameIndex() const noexcept { return endFrameIndex; } - inline float GetTotalDuration() const noexcept { return duration; } + inline int GetEndFrameIndex() const noexcept { return endFrameIndex; }\ inline float GetStartTimeStamp() const noexcept { return startTimeStamp; } + inline float GetPlaybackSpeedMultiplier() const noexcept { return playbackSpeedMultiplier; } + /// + /// Retrieves the duration of the animation as if the playback speed multiplier is + /// in it's default value of 1.0f. + /// + /// Duration of the animation in seconds. + inline float GetTotalDuration() const noexcept { return duration; } + /// + /// Retrieves the duration of the animation with the playback speed multiplier + /// taken into account. + /// + /// True duration of the animation in seconds. + inline float GetTrueDuration() const noexcept { return duration / playbackSpeedMultiplier; } private: /*---------------------------------------------------------------------------------*/ /* Data Members */ /*---------------------------------------------------------------------------------*/ Handle rawAnim; - int startFrameIndex; // First Frame - int endFrameIndex; // Last Frame (inclusive) - float duration; // Total playback time - float startTimeStamp; // Starting time stamp of the raw anim + int startFrameIndex; // First Frame + int endFrameIndex; // Last Frame (inclusive) + float duration; // Total playback time + float startTimeStamp; // Starting time stamp of the raw anim + float playbackSpeedMultiplier; // Multiplier applied to the playback of an animation clip }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Animation/SHAnimationController.cpp b/SHADE_Engine/src/Animation/SHAnimationController.cpp index 3c04614a..e105c0da 100644 --- a/SHADE_Engine/src/Animation/SHAnimationController.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationController.cpp @@ -62,18 +62,21 @@ namespace SHADE if (!instData.CurrentNode) return; + // Get the clip + Handle clip = instData.CurrentNode->Clip; + // Update the current playback - instData.ClipPlaybackTime += dt; + instData.ClipPlaybackTime += dt * clip->GetPlaybackSpeedMultiplier(); // Check if we finished playing - const float CLIP_CURR_PLAYED_TIME = instData.ClipPlaybackTime - instData.CurrentNode->Clip->GetStartTimeStamp(); - if (CLIP_CURR_PLAYED_TIME > instData.CurrentNode->Clip->GetTotalDuration()) + const float CLIP_CURR_PLAYED_TIME = instData.ClipPlaybackTime - clip->GetStartTimeStamp(); + if (CLIP_CURR_PLAYED_TIME > clip->GetTotalDuration()) { // Clamp - instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp() + instData.CurrentNode->Clip->GetTotalDuration(); + instData.ClipPlaybackTime = clip->GetStartTimeStamp() + clip->GetTotalDuration(); // Go to next state - Handle originalClip = instData.CurrentNode->Clip; + Handle originalClip = clip; bool stateChanged = false; for (const auto& transition : instData.CurrentNode->Transitions) { diff --git a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp index 294d8098..923fb876 100644 --- a/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp +++ b/SHADE_Engine/src/Animation/SHAnimatorComponent.cpp @@ -254,7 +254,7 @@ namespace SHADE } void SHAnimatorComponent::updateManualClipState(float dt) { - currPlaybackTime += dt; + currPlaybackTime += dt * currClip->GetPlaybackSpeedMultiplier(); const float CLIP_CURR_PLAYED_TIME = currPlaybackTime - currClip->GetStartTimeStamp(); if (CLIP_CURR_PLAYED_TIME > currClip->GetTotalDuration()) { diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h index 28d3b697..15fc449d 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h @@ -26,6 +26,7 @@ namespace SHADE uint32_t firstIndex; uint32_t lastIndex; AssetID animRawDataAssetId; // Not serialised, only populated during runtime from parent asset + float playbackMultiplier = 1.0f; }; struct SH_API SHAnimClipContainerAsset final : SHAssetData diff --git a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp index 332bf6e9..e85efaf4 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.cpp @@ -54,6 +54,7 @@ namespace SHADE newAssetName.clear(); firstIndex = 0; lastIndex = rawAnimation->GetTotalFrames(); + playbackMultiplier = 1.0f; } // Assign callback @@ -72,6 +73,9 @@ namespace SHADE SHEditorUI::PushID(1); SHEditorUI::InputUnsignedInt("Last Frame Index", lastIndex); SHEditorUI::PopID(); + SHEditorUI::PushID(2); + SHEditorUI::InputFloat("Playback Multiplier", playbackMultiplier); + SHEditorUI::PopID(); // Invalid values const bool INVALID_CONFIG = newAssetName.empty() || firstIndex > lastIndex; @@ -88,6 +92,7 @@ namespace SHADE animClip->firstIndex = firstIndex; animClip->lastIndex = lastIndex; animClip->animRawDataAssetId = SHResourceManager::GetAssetID(rawAnimation).value_or(0); + animClip->playbackMultiplier = playbackMultiplier; SHAssetManager::SaveAsset(containerAsset->id); // Close @@ -168,6 +173,7 @@ namespace SHADE int firstIndex = animClip->GetStartFrameIndex(); int endIndex = animClip->GetEndFrameIndex(); + float playbackMp = animClip->GetPlaybackSpeedMultiplier(); ImGui::Separator(); ImGui::Text(animClipName.has_value() ? animClipName.value().c_str() : ""); @@ -183,12 +189,18 @@ namespace SHADE [&]() { return endIndex; }, [&](int i) { endIndex = i; } ); + changed |= SHEditorWidgets::DragFloat + ( + "Playback Multiplier", + [&]() { return playbackMp; }, + [&](float f) { playbackMp = f; } + ); // If there's a change we need to commit changes if (changed && firstIndex < endIndex) { // Update runtime asset - *animClip = SHAnimationClip(currRawAnim, firstIndex, endIndex); + *animClip = SHAnimationClip(currRawAnim, firstIndex, endIndex, playbackMp); // Update serialized asset auto assetId = SHResourceManager::GetAssetID(animClip); @@ -197,6 +209,7 @@ namespace SHADE auto const animAsset = SHAssetManager::GetData(assetId.value()); animAsset->firstIndex = firstIndex; animAsset->lastIndex = endIndex; + animAsset->playbackMultiplier = playbackMp; SHAssetManager::SaveAsset(containerAsset->id); } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h index 6790cded..550bd158 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h +++ b/SHADE_Engine/src/Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h @@ -62,6 +62,7 @@ namespace SHADE std::string newAssetName; uint32_t firstIndex = 0; uint32_t lastIndex = 0; + float playbackMultiplier = 1.0f; Handle rawAnimation; SHAsset* containerAsset{nullptr}; SHAnimClipContainerAsset* container{nullptr}; diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index 6474b478..d2bc9241 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -372,7 +372,8 @@ namespace SHADE ( LoadOrGet(assetData.animRawDataAssetId), assetData.firstIndex, - assetData.lastIndex + assetData.lastIndex, + assetData.playbackMultiplier ); } else if constexpr (std::is_same_v) From 3ca463aa2196eda31fc8f4c05f26fcc979aacbf6 Mon Sep 17 00:00:00 2001 From: XiaoQiDigipen <72735604+XiaoQiDigipen@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:47:08 +0800 Subject: [PATCH 2/2] Added serialisation of extra time multiplier field in animation clip asset Fixed bug when creating animation clip --- ..._RigTest01_SkinningTestAnims.shanimcontainer | Bin 24 -> 28 bytes .../Animation Clips/racoonAnims.shanimcontainer | Bin 231 -> 279 bytes .../src/Application/SBApplication.cpp | 4 ++-- .../Asset Types/SHAnimClipContainerAsset.h | 2 +- .../Assets/Libraries/Loaders/SHBinaryLoader.cpp | 4 ++-- SHADE_Engine/src/Assets/SHAssetManager.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer b/Assets/Animation Clips/MD_RigTest01_SkinningTestAnims.shanimcontainer index 5d6924e2be094865660e35de817f0e71ebd1574b..c14d75f4a06f920f82b7f6a5928a0208999b2462 100644 GIT binary patch delta 9 Qcmb1;nIOT!z|de100)!-pa1{> delta 4 Lcmb1>ZF0rUXf diff --git a/Assets/Animation Clips/racoonAnims.shanimcontainer b/Assets/Animation Clips/racoonAnims.shanimcontainer index c0b335cf09d328278c77c7263f3e4d57d283dea9..2cd476937aba0f8b186c0e97c724b43c46a946c5 100644 GIT binary patch literal 279 zcmaExu$YC1fq{V)h(iMMi&KF#11E@JXs~AilAb9!sa!x>2_ys*V+N8zrFj}a$^nQ$ zLTo@XATv3;w7?C>3IhoOMM0XJ6N`!}<3UD50eM9r37`zfc!&(ppb8*o0!SPv0d_=2 zQGWR}Aa@y55M+9AK~ZL2$toag7gQ8vx>sp#L40sYVo}LHAnzzt24p%|#wS0&;24l| e4l2O`lW@&TIS*uCgNlQE=~kMP1LEF=iU9y*Lp9z2 literal 231 zcmaExu$YC1fq{V)h(iMMi&KF#11Au(0I_FEPAV6WRsv#XAPy?c(*RNqK+Fcj0h!6! zr3G$4Ru~Y26gnps6;;NAv_%1VML-NP3L*;BTmj@v0AjFZ8AbW!(}0|1KnyZ1xS%LA zuVfXFwF`(rrg@d-7Q_daBo>wI1M-dnF~~Hqs84==!7(7`91wHB1YPq|&I8%kfEeU@ Nx6+&(AjNPOhykn?Eb0IN diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 3943b34d..42e112b8 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -180,8 +180,8 @@ namespace Sandbox // Link up SHDebugDraw SHDebugDraw::Init(SHSystemManager::GetSystem()); - auto clip = SHResourceManager::LoadOrGet(77816045); - auto rig = SHResourceManager::LoadOrGet(77816045); + //auto clip = SHResourceManager::LoadOrGet(77816045); + //auto rig = SHResourceManager::LoadOrGet(77816045); } void SBApplication::Update(void) diff --git a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h index 15fc449d..7a719685 100644 --- a/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h +++ b/SHADE_Engine/src/Assets/Asset Types/SHAnimClipContainerAsset.h @@ -25,8 +25,8 @@ namespace SHADE std::string name; uint32_t firstIndex; uint32_t lastIndex; - AssetID animRawDataAssetId; // Not serialised, only populated during runtime from parent asset float playbackMultiplier = 1.0f; + AssetID animRawDataAssetId; // Not serialised, only populated during runtime from parent asset }; struct SH_API SHAnimClipContainerAsset final : SHAssetData diff --git a/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp b/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp index 119bd9aa..a8663dde 100644 --- a/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp +++ b/SHADE_Engine/src/Assets/Libraries/Loaders/SHBinaryLoader.cpp @@ -79,7 +79,7 @@ namespace SHADE file.write( reinterpret_cast(&clip->firstIndex), - sizeof(uint32_t) * 2 + sizeof(uint32_t) * 3 ); } } @@ -118,7 +118,7 @@ namespace SHADE file.read( reinterpret_cast(&clip->firstIndex), - sizeof(uint32_t) * 2 + sizeof(uint32_t) * 3 ); clip->animRawDataAssetId = data->animRawDataAssetId; diff --git a/SHADE_Engine/src/Assets/SHAssetManager.cpp b/SHADE_Engine/src/Assets/SHAssetManager.cpp index 8cddaf2c..dc9d9587 100644 --- a/SHADE_Engine/src/Assets/SHAssetManager.cpp +++ b/SHADE_Engine/src/Assets/SHAssetManager.cpp @@ -313,7 +313,7 @@ namespace SHADE .isSubAsset = true, .parent = parent }; - auto& newClip {animContainer->clips.emplace_back()}; + auto& newClip {animContainer->clips.emplace_back(new SHAnimClipAsset())}; newClip->name = name; assetCollection.emplace(id, asset); assetCollection[parent].subAssets.push_back(&assetCollection[id]);