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();