diff --git a/Source/Engine/Animations/AnimationManager.cpp b/Source/Engine/Animations/AnimationManager.cpp index c64a61856..e96ebf40e 100644 --- a/Source/Engine/Animations/AnimationManager.cpp +++ b/Source/Engine/Animations/AnimationManager.cpp @@ -6,7 +6,8 @@ #include "Engine/Engine/Time.h" #include "Engine/Engine/EngineService.h" -Array UpdateList(256); +Array UpdateList; +Array UpdateBones; class AnimationManagerService : public EngineService { @@ -67,9 +68,24 @@ void AnimationManagerService::Update() } animatedModel->GraphInstance.LastUpdateTime = t; - const auto bones = graph->GraphExecutor.Update(animatedModel->GraphInstance, dt); + // Evaluate animated nodes pose + graph->GraphExecutor.Update(animatedModel->GraphInstance, dt); + + // Calculate the final bones transformations + { + ANIM_GRAPH_PROFILE_EVENT("Final Pose"); + auto& skeleton = animatedModel->SkinnedModel->Skeleton; + UpdateBones.Resize(skeleton.Bones.Count(), false); + for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++) + { + auto& bone = skeleton.Bones[boneIndex]; + UpdateBones[boneIndex] = bone.OffsetMatrix * animatedModel->GraphInstance.NodesPose[bone.NodeIndex]; + } + } + + // Update gameplay const bool usePrevFrameBones = animatedModel->PerBoneMotionBlur; - animatedModel->_skinningData.SetData(bones, !usePrevFrameBones); + animatedModel->_skinningData.SetData(UpdateBones.Get(), !usePrevFrameBones); animatedModel->OnAnimUpdate(); } } @@ -79,6 +95,7 @@ void AnimationManagerService::Update() void AnimationManagerService::Dispose() { UpdateList.Resize(0); + UpdateBones.Resize(0); } void AnimationManager::AddToUpdate(AnimatedModel* obj) diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp index 91ef2cc54..22fc6af28 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp @@ -152,8 +152,8 @@ bool AnimGraph::IsReady() const bool AnimGraph::CanUseWithSkeleton(SkinnedModel* other) const { - // All data loaded and bones count the same - return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count(); + // All data loaded and nodes count the same + return IsReady() && other && other->IsLoaded() && other->Skeleton.Nodes.Count() == BaseModel->Skeleton.Nodes.Count(); } void AnimGraph::ClearCustomNode(Node* node) diff --git a/Source/Engine/Animations/Graph/AnimGraph.cpp b/Source/Engine/Animations/Graph/AnimGraph.cpp index 8ef9adcdb..2932f7c3f 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.cpp @@ -175,7 +175,7 @@ AnimGraphExecutor::AnimGraphExecutor(AnimGraph& graph) _perGroupProcessCall[16] = (ProcessBoxHandler)&AnimGraphExecutor::ProcessGroupFunction; } -const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt) +void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt) { ASSERT(data.Parameters.Count() == _graph.Parameters.Count()); @@ -185,7 +185,6 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt) ANIM_GRAPH_PROFILE_EVENT("Init"); // Prepare graph data for the evaluation - _skeletonBonesCount = skeleton.Bones.Count(); _skeletonNodesCount = skeleton.Nodes.Count(); _graphStack.Clear(); _graphStack.Push((Graph*)&_graph); @@ -265,23 +264,19 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt) _data->RootMotion = animResult->RootMotion; } - // Calculate the final bones transformations - { - ANIM_GRAPH_PROFILE_EVENT("Final Pose"); - - _bonesTransformations.Resize(_skeletonBonesCount, false); - - for (int32 boneIndex = 0; boneIndex < _skeletonBonesCount; boneIndex++) - { - auto& bone = skeleton.Bones[boneIndex]; - _bonesTransformations[boneIndex] = bone.OffsetMatrix * _data->NodesPose[bone.NodeIndex]; - } - } - // Cleanup _data = nullptr; +} - return _bonesTransformations.Get(); +void AnimGraphExecutor::GetInputValue(Box* box, Value& result) +{ + result = eatBox(box->GetParent(), box->FirstConnection()); +} + +void AnimGraphExecutor::ResetBucket(int32 bucketIndex) +{ + auto& stateBucket = _data->State[bucketIndex]; + _graph._bucketInitializerList[bucketIndex](stateBucket); } void AnimGraphExecutor::ResetBuckets(AnimGraphBase* graph) diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h index 3b7aa0030..8ca4b7247 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.h +++ b/Source/Engine/Animations/Graph/AnimGraph.h @@ -817,12 +817,10 @@ private: AnimGraph& _graph; float _deltaTime = 0.0f; uint64 _currentFrameIndex = 0; - int32 _skeletonBonesCount = 0; int32 _skeletonNodesCount = 0; RootMotionMode _rootMotionMode = RootMotionMode::NoExtraction; AnimGraphInstanceData* _data = nullptr; AnimGraphImpulse _emptyNodes; - Array _bonesTransformations; AnimGraphTransitionData _transitionData; Array> _callStack; Array> _graphStack; @@ -853,18 +851,13 @@ public: /// /// The instance data. /// The delta time (in seconds). - /// The pointer to the final bones structure as a result of the animation evaluation. - const Matrix* Update(AnimGraphInstanceData& data, float dt); + void Update(AnimGraphInstanceData& data, float dt); - void GetInputValue(Box* box, Value& result) - { - result = eatBox(box->GetParent(), box->FirstConnection()); - } + void GetInputValue(Box* box, Value& result); /// /// Gets the skeleton nodes transformations structure containing identity matrices. /// - /// The data. FORCE_INLINE const AnimGraphImpulse* GetEmptyNodes() const { return &_emptyNodes; @@ -914,11 +907,7 @@ public: /// Resets the state bucket. /// /// The zero-based index of the bucket. - FORCE_INLINE void ResetBucket(int32 bucketIndex) - { - auto& stateBucket = _data->State[bucketIndex]; - _graph._bucketInitializerList[bucketIndex](stateBucket); - } + void ResetBucket(int32 bucketIndex); /// /// Resets all the state bucket used by the given graph including sub-graphs (total). Can eb used to reset the animation state of the nested graph (including children). diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index e13714f2c..d7baadfc0 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -636,7 +636,8 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One); // Skip if no change will be performed - if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity())) + auto& skeleton = _graph.BaseModel->Skeleton; + if (boneIndex < 0 || boneIndex >= skeleton.Bones.Count() || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity())) { // Pass through the input value = Value::Null; @@ -767,8 +768,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu const auto copyScale = (bool)node->Values[4]; // Skip if no change will be performed - if (srcBoneIndex < 0 || srcBoneIndex >= _skeletonBonesCount || - dstBoneIndex < 0 || dstBoneIndex >= _skeletonBonesCount || + const auto& skeleton = _graph.BaseModel->Skeleton; + if (srcBoneIndex < 0 || srcBoneIndex >= skeleton.Bones.Count() || + dstBoneIndex < 0 || dstBoneIndex >= skeleton.Bones.Count() || !(copyTranslation || copyRotation || copyScale)) { // Pass through the input @@ -776,7 +778,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu box->Cache = value; return; } - const auto& skeleton = _graph.BaseModel->Skeleton; // Copy bone data Transform srcTransform = nodes->Nodes[skeleton.Bones[srcBoneIndex].NodeIndex]; @@ -800,7 +801,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu const auto boneIndex = (int32)node->Values[0]; const auto& skeleton = _graph.BaseModel->Skeleton; const auto input = tryGetValue(node->GetBox(0), Value::Null); - if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < _skeletonBonesCount) + if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < skeleton.Bones.Count()) value = Variant(((AnimGraphImpulse*)input.AsPointer)->Nodes[skeleton.Bones[boneIndex].NodeIndex]); else value = Variant(Transform::Identity);