From 830db22dcc306618f87768326d0c8df8d98c48b5 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 9 Aug 2024 09:05:53 -0500 Subject: [PATCH] Blend out of anim slots when stopped. --- .../Animations/Graph/AnimGroup.Animation.cpp | 65 ++++++++++++++++--- Source/Engine/Level/Actors/AnimatedModel.cpp | 2 +- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 7538e06b5..6763f6d5d 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -2237,8 +2237,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu { // Start playing animation bucket.Index = i; - bucket.TimePosition = 0.0f; - bucket.BlendInPosition = 0.0f; + // Keep bucket time position and blend in time for if blending between two anims in the same slot. + bucket.TimePosition = bucket.TimePosition; + bucket.BlendInPosition = bucket.BlendInPosition; bucket.BlendOutPosition = 0.0f; bucket.LoopsDone = 0; bucket.LoopsLeft = slot.LoopCount; @@ -2248,6 +2249,12 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu if (bucket.Index == -1 || !slots[bucket.Index].Animation->IsLoaded()) { value = tryGetValue(node->GetBox(1), Value::Null); + // Reset times if time is left over from playing between different anims in the same slot. + if (bucket.BlendInPosition > 0) + { + bucket.TimePosition = 0; + bucket.BlendInPosition = 0; + } return; } } @@ -2256,12 +2263,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu auto& slot = slots[bucket.Index]; Animation* anim = slot.Animation; ASSERT(slot.Animation && slot.Animation->IsLoaded()); - if (slot.Reset) - { - // Start from the begining - slot.Reset = false; - bucket.TimePosition = 0.0f; - } const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed; const float length = anim->GetLength(); const bool loop = bucket.LoopsLeft != 0; @@ -2285,6 +2286,54 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu // Speed is accounted for in the new time pos, so keep sample speed at 1 value = SampleAnimation(node, loop, length, 0.0f, bucket.TimePosition, newTimePos, anim, 1); bucket.TimePosition = newTimePos; + + // On animation slot stop + if (slot.Reset) + { + // Blend between last anim and new anim if found, otherwise blend back to input. + Animation* sAnim = nullptr; + for (int32 i = 0; i < slots.Count(); i++) + { + auto& s = slots[i]; + if (s.Animation && s.Name == slotName && s.Animation != slot.Animation) + { + sAnim = s.Animation; + } + } + float oldTimePos = bucket.BlendOutPosition; + bucket.BlendOutPosition += deltaTime; + bucket.BlendInPosition = bucket.BlendOutPosition; + const float alpha = bucket.BlendOutPosition / slot.BlendOutTime; + if (sAnim != nullptr) + { + auto sValue = SampleAnimation(node, false, sAnim->GetLength(), 0.0f, oldTimePos, bucket.BlendInPosition, sAnim, 1); + //value = SampleAnimationsWithBlend(node, false, length, 0.0f, bucket.TimePosition, newTimePos, anim, sAnim, 1, 1, alpha); + value = Blend(node, value, sValue, alpha, AlphaBlendMode::HermiteCubic); + } + else + { + auto input = tryGetValue(node->GetBox(1), Value::Null); + value = Blend(node, value, input, alpha, AlphaBlendMode::HermiteCubic); + } + + if (bucket.BlendOutPosition >= slot.BlendOutTime) + { + // Start from the beginning or the blend in position if next anim found. + slot.Animation = nullptr; + slot.Reset = false; + if (!sAnim) + { + bucket.TimePosition = 0; + bucket.BlendInPosition = 0; + } + else + { + bucket.TimePosition = bucket.BlendInPosition; + } + } + break; + } + if (bucket.LoopsLeft == 0 && slot.BlendOutTime > 0.0f && length - slot.BlendOutTime < bucket.TimePosition) { // Blend out diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 2c0e8474d..0eab292c5 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -506,7 +506,7 @@ void AnimatedModel::StopSlotAnimation(const StringView& slotName, Animation* ani { if (slot.Animation == anim && slot.Name == slotName) { - slot.Animation = nullptr; + //slot.Animation = nullptr; slot.Reset = true; break; }