diff --git a/Source/Engine/Animations/AnimationGraph.cs b/Source/Engine/Animations/AnimationGraph.cs index 7de45768e..baf3e1b4c 100644 --- a/Source/Engine/Animations/AnimationGraph.cs +++ b/Source/Engine/Animations/AnimationGraph.cs @@ -175,12 +175,7 @@ namespace FlaxEngine /// /// The root motion data. /// - public Vector3 RootMotionTranslation; - - /// - /// The root motion data. - /// - public Quaternion RootMotionRotation; + public Transform RootMotion; /// /// The animation time position (in seconds). @@ -251,8 +246,7 @@ namespace FlaxEngine destination->NodesCount = source->NodesCount; destination->Unused = source->Unused; Utils.MemoryCopy(new IntPtr(destination->Nodes), new IntPtr(source->Nodes), (ulong)(source->NodesCount * sizeof(Transform))); - destination->RootMotionTranslation = source->RootMotionTranslation; - destination->RootMotionRotation = source->RootMotionRotation; + destination->RootMotion = source->RootMotion; destination->Position = source->Position; destination->Length = source->Length; } diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp index 5f9e7d75a..d74c523f1 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp @@ -39,8 +39,7 @@ struct InternalImpulse int32 NodesCount; int32 Unused; Transform* Nodes; - Vector3 RootMotionTranslation; - Quaternion RootMotionRotation; + Transform RootMotion; float Position; float Length; }; diff --git a/Source/Engine/Animations/Graph/AnimGraph.cpp b/Source/Engine/Animations/Graph/AnimGraph.cpp index f10275c6b..71c9534e0 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.cpp @@ -11,53 +11,6 @@ extern void RetargetSkeletonNode(const SkeletonData& sourceSkeleton, const Skele ThreadLocal AnimGraphExecutor::Context; -RootMotionData RootMotionData::Identity = { Vector3(0.0f), Quaternion(0.0f, 0.0f, 0.0f, 1.0f) }; - -RootMotionData& RootMotionData::operator+=(const RootMotionData& b) -{ - Translation += b.Translation; - Rotation *= b.Rotation; - return *this; -} - -RootMotionData& RootMotionData::operator+=(const Transform& b) -{ - Translation += b.Translation; - Rotation *= b.Orientation; - return *this; -} - -RootMotionData& RootMotionData::operator-=(const Transform& b) -{ - Translation -= b.Translation; - Quaternion invRotation = Rotation; - invRotation.Invert(); - Quaternion::Multiply(invRotation, b.Orientation, Rotation); - return *this; -} - -RootMotionData RootMotionData::operator+(const RootMotionData& b) const -{ - RootMotionData result; - - result.Translation = Translation + b.Translation; - result.Rotation = Rotation * b.Rotation; - - return result; -} - -RootMotionData RootMotionData::operator-(const RootMotionData& b) const -{ - RootMotionData result; - - result.Rotation = Rotation; - result.Rotation.Invert(); - Vector3::Transform(b.Translation - Translation, result.Rotation, result.Translation); - Quaternion::Multiply(result.Rotation, b.Rotation, result.Rotation); - - return result; -} - Transform AnimGraphImpulse::GetNodeModelTransformation(SkeletonData& skeleton, int32 nodeIndex) const { const int32 parentIndex = skeleton.Nodes[nodeIndex].ParentIndex; @@ -89,7 +42,7 @@ void AnimGraphInstanceData::Clear() LastUpdateTime = -1; CurrentFrame = 0; RootTransform = Transform::Identity; - RootMotion = RootMotionData::Identity; + RootMotion = Transform::Identity; Parameters.Resize(0); State.Resize(0); NodesPose.Resize(0); @@ -105,7 +58,7 @@ void AnimGraphInstanceData::ClearState() LastUpdateTime = -1; CurrentFrame = 0; RootTransform = Transform::Identity; - RootMotion = RootMotionData::Identity; + RootMotion = Transform::Identity; State.Resize(0); NodesPose.Resize(0); Slots.Clear(); @@ -259,7 +212,7 @@ void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt) e.Hit = false; // Init empty nodes data - context.EmptyNodes.RootMotion = RootMotionData::Identity; + context.EmptyNodes.RootMotion = Transform::Identity; context.EmptyNodes.Position = 0.0f; context.EmptyNodes.Length = 0.0f; context.EmptyNodes.Nodes.Resize(_skeletonNodesCount, false); diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h index 70234ea01..7ed3e275f 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.h +++ b/Source/Engine/Animations/Graph/AnimGraph.h @@ -26,58 +26,6 @@ class AnimGraphExecutor; class SkinnedModel; class SkeletonData; -/// -/// The root motion data container. Supports displacement and rotation (no scale component). -/// -struct RootMotionData -{ - static RootMotionData Identity; - - Vector3 Translation; - Quaternion Rotation; - - RootMotionData() - { - } - - RootMotionData(const Vector3& translation, const Quaternion& rotation) - { - Translation = translation; - Rotation = rotation; - } - - RootMotionData(const RootMotionData& other) - { - Translation = other.Translation; - Rotation = other.Rotation; - } - - explicit RootMotionData(const Transform& other) - { - Translation = other.Translation; - Rotation = other.Orientation; - } - - RootMotionData& operator=(const Transform& other) - { - Translation = other.Translation; - Rotation = other.Orientation; - return *this; - } - - RootMotionData& operator+=(const RootMotionData& b); - RootMotionData& operator+=(const Transform& b); - RootMotionData& operator-=(const Transform& b); - RootMotionData operator+(const RootMotionData& b) const; - RootMotionData operator-(const RootMotionData& b) const; - - static void Lerp(const RootMotionData& t1, const RootMotionData& t2, float amount, RootMotionData& result) - { - Vector3::Lerp(t1.Translation, t2.Translation, amount, result.Translation); - Quaternion::Slerp(t1.Rotation, t2.Rotation, amount, result.Rotation); - } -}; - /// /// The animation graph 'impulse' connections data container (the actual transfer is done via pointer as it gives better performance). /// Container for skeleton nodes transformation hierarchy and any other required data. @@ -93,7 +41,7 @@ struct FLAXENGINE_API AnimGraphImpulse /// /// The root motion extracted from the animation to apply on animated object. /// - RootMotionData RootMotion = RootMotionData::Identity; + Transform RootMotion = Transform::Identity; /// /// The animation time position (in seconds). @@ -348,7 +296,7 @@ public: /// /// The current root motion delta to apply on a target object. /// - RootMotionData RootMotion = RootMotionData::Identity; + Transform RootMotion = Transform::Identity; /// /// The animation graph parameters collection (instanced, override the default values). @@ -883,7 +831,7 @@ private: }; int32 GetRootNodeIndex(Animation* anim); - void ExtractRootMotion(Span mapping, int32 rootNodeIndex, Animation* anim, float pos, float prevPos, Transform& rootNode, RootMotionData& rootMotion); + void ExtractRootMotion(Span mapping, int32 rootNodeIndex, Animation* anim, float pos, float prevPos, Transform& rootNode, Transform& rootMotion); void ProcessAnimEvents(AnimGraphNode* node, bool loop, float length, float animPos, float animPrevPos, Animation* anim, float speed); void ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* node, bool loop, float length, float pos, float prevPos, Animation* anim, float speed, float weight = 1.0f, ProcessAnimationMode mode = ProcessAnimationMode::Override); Variant SampleAnimation(AnimGraphNode* node, bool loop, float length, float startTimePos, float prevTimePos, float& newTimePos, Animation* anim, float speed); diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 3be8e85da..ccdefb9d3 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -58,7 +58,7 @@ int32 AnimGraphExecutor::GetRootNodeIndex(Animation* anim) return rootNodeIndex; } -void AnimGraphExecutor::ExtractRootMotion(const Span mapping, int32 rootNodeIndex, Animation* anim, float pos, float prevPos, Transform& rootNode, RootMotionData& rootMotion) +void AnimGraphExecutor::ExtractRootMotion(const Span mapping, int32 rootNodeIndex, Animation* anim, float pos, float prevPos, Transform& rootNode, Transform& rootMotion) { const Transform& refPose = GetEmptyNodes()->Nodes[rootNodeIndex]; const int32 nodeToChannel = mapping[rootNodeIndex]; @@ -88,15 +88,15 @@ void AnimGraphExecutor::ExtractRootMotion(const Span mapping, int32 rootN // (end - before + now - begin) // It sums the motion since the last update to anim end and since the start to now rootMotion.Translation = rootEnd.Translation - rootBefore.Translation + rootNode.Translation - rootBegin.Translation; - rootMotion.Rotation = rootEnd.Orientation * rootBefore.Orientation.Conjugated() * (rootNode.Orientation * rootBegin.Orientation.Conjugated()); - //rootMotion.Rotation = Quaternion::Identity; + rootMotion.Orientation = rootEnd.Orientation * rootBefore.Orientation.Conjugated() * (rootNode.Orientation * rootBegin.Orientation.Conjugated()); + //rootMotion.Orientation = Quaternion::Identity; } else { // Simple motion delta // (now - before) rootMotion.Translation = rootNode.Translation - rootBefore.Translation; - rootMotion.Rotation = rootBefore.Orientation.Conjugated() * rootNode.Orientation; + rootMotion.Orientation = rootBefore.Orientation.Conjugated() * rootNode.Orientation; } } @@ -335,25 +335,25 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* // Calculate the root motion node transformation const int32 rootNodeIndex = GetRootNodeIndex(anim); Transform rootNode = emptyNodes->Nodes[rootNodeIndex]; - RootMotionData& dstNode = nodes->RootMotion; - RootMotionData srcNode(rootNode); + Transform& dstNode = nodes->RootMotion; + Transform srcNode(rootNode); ExtractRootMotion(mapping.NodesMapping, rootNodeIndex, anim, animPos, animPrevPos, rootNode, srcNode); // Blend root motion if (mode == ProcessAnimationMode::BlendAdditive) { dstNode.Translation += srcNode.Translation * weight; - BlendAdditiveWeightedRotation(dstNode.Rotation, srcNode.Rotation, weight); + BlendAdditiveWeightedRotation(dstNode.Orientation, srcNode.Orientation, weight); } else if (mode == ProcessAnimationMode::Add) { dstNode.Translation += srcNode.Translation * weight; - dstNode.Rotation += srcNode.Rotation * weight; + dstNode.Orientation += srcNode.Orientation * weight; } else if (weighted) { dstNode.Translation = srcNode.Translation * weight; - dstNode.Rotation = srcNode.Rotation * weight; + dstNode.Orientation = srcNode.Orientation * weight; } else { @@ -410,7 +410,7 @@ Variant AnimGraphExecutor::SampleAnimationsWithBlend(AnimGraphNode* node, bool l } if (_rootMotionMode != RootMotionMode::NoExtraction) { - nodes->RootMotion.Rotation.Normalize(); + nodes->RootMotion.Orientation.Normalize(); } return nodes; @@ -444,7 +444,7 @@ Variant AnimGraphExecutor::SampleAnimationsWithBlend(AnimGraphNode* node, bool l } if (_rootMotionMode != RootMotionMode::NoExtraction) { - nodes->RootMotion.Rotation.Normalize(); + nodes->RootMotion.Orientation.Normalize(); } return nodes; @@ -469,7 +469,7 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const { Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]); } - RootMotionData::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); + Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); nodes->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha); nodes->Length = Math::Lerp(nodesA->Length, nodesB->Length, alpha); @@ -1017,7 +1017,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu { Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]); } - RootMotionData::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); + Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); value = nodes; } @@ -1063,7 +1063,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu t.Orientation.Normalize(); Transform::Lerp(tA, t, alpha, nodes->Nodes[i]); } - RootMotionData::Lerp(nodesA->RootMotion, nodesA->RootMotion + nodesB->RootMotion, alpha, nodes->RootMotion); + Transform::Lerp(nodesA->RootMotion, nodesA->RootMotion + nodesB->RootMotion, alpha, nodes->RootMotion); value = nodes; } } @@ -1111,7 +1111,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu nodes->Nodes[nodeIndex] = tA; } } - RootMotionData::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); + Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); value = nodes; } @@ -1496,7 +1496,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu value = poseData->RootMotion.Translation; break; case 1: - value = poseData->RootMotion.Rotation; + value = poseData->RootMotion.Orientation; break; } } @@ -1528,7 +1528,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu auto nodes = node->GetNodes(this); nodes->Nodes = poseData->Nodes; nodes->RootMotion.Translation = (Vector3)tryGetValue(node->GetBox(2), Value::Zero); - nodes->RootMotion.Rotation = (Quaternion)tryGetValue(node->GetBox(3), Value::Zero); + nodes->RootMotion.Orientation = (Quaternion)tryGetValue(node->GetBox(3), Value::Zero); value = nodes; break; } @@ -1546,7 +1546,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu auto nodes = node->GetNodes(this); nodes->Nodes = poseData->Nodes; nodes->RootMotion.Translation = poseData->RootMotion.Translation + (Vector3)tryGetValue(node->GetBox(2), Value::Zero); - nodes->RootMotion.Rotation = poseData->RootMotion.Rotation * (Quaternion)tryGetValue(node->GetBox(3), Value::Zero); + nodes->RootMotion.Orientation = poseData->RootMotion.Orientation * (Quaternion)tryGetValue(node->GetBox(3), Value::Zero); value = nodes; break; } diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index d0ba2ec63..882026db7 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -419,10 +419,10 @@ bool AnimatedModel::IsPlayingSlotAnimation(const StringView& slotName, Animation return false; } -void AnimatedModel::ApplyRootMotion(const RootMotionData& rootMotionDelta) +void AnimatedModel::ApplyRootMotion(const Transform& rootMotionDelta) { // Skip if no motion - if (rootMotionDelta.Translation.IsZero() && rootMotionDelta.Rotation.IsIdentity()) + if (rootMotionDelta.Translation.IsZero() && rootMotionDelta.Orientation.IsIdentity()) return; // Transform translation from actor space into world space @@ -430,7 +430,7 @@ void AnimatedModel::ApplyRootMotion(const RootMotionData& rootMotionDelta) // Apply movement Actor* target = RootMotionTarget ? RootMotionTarget.Get() : this; - target->AddMovement(translation, rootMotionDelta.Rotation); + target->AddMovement(translation, rootMotionDelta.Orientation); } void AnimatedModel::SyncParameters() diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index f7bed48d5..ccd0ee3b5 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -344,7 +344,7 @@ public: API_FUNCTION() bool IsPlayingSlotAnimation(const StringView& slotName, Animation* anim); private: - void ApplyRootMotion(const RootMotionData& rootMotionDelta); + void ApplyRootMotion(const Transform& rootMotionDelta); void SyncParameters(); void Update();