Fix Blend Poses nodes to smoothly blend back when transition goes back
#3595
This commit is contained in:
@@ -93,6 +93,7 @@ void MultiBlendBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
|||||||
void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
||||||
{
|
{
|
||||||
bucket.BlendPose.TransitionPosition = 0.0f;
|
bucket.BlendPose.TransitionPosition = 0.0f;
|
||||||
|
bucket.BlendPose.BlendPoseIndex = -1;
|
||||||
bucket.BlendPose.PreviousBlendPoseIndex = -1;
|
bucket.BlendPose.PreviousBlendPoseIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,8 @@ public:
|
|||||||
struct BlendPoseBucket
|
struct BlendPoseBucket
|
||||||
{
|
{
|
||||||
float TransitionPosition;
|
float TransitionPosition;
|
||||||
int32 PreviousBlendPoseIndex;
|
int16 BlendPoseIndex;
|
||||||
|
int16 PreviousBlendPoseIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateMachineBucket
|
struct StateMachineBucket
|
||||||
|
|||||||
@@ -676,9 +676,12 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const
|
|||||||
if (!ANIM_GRAPH_IS_VALID_PTR(poseB))
|
if (!ANIM_GRAPH_IS_VALID_PTR(poseB))
|
||||||
nodesB = GetEmptyNodes();
|
nodesB = GetEmptyNodes();
|
||||||
|
|
||||||
|
const Transform* srcA = nodesA->Nodes.Get();
|
||||||
|
const Transform* srcB = nodesB->Nodes.Get();
|
||||||
|
Transform* dst = nodes->Nodes.Get();
|
||||||
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
|
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
|
||||||
{
|
{
|
||||||
Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
|
Transform::Lerp(srcA[i], srcB[i], alpha, dst[i]);
|
||||||
}
|
}
|
||||||
Transform::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->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha);
|
||||||
@@ -1263,21 +1266,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
|||||||
{
|
{
|
||||||
const auto valueA = tryGetValue(node->GetBox(1), Value::Null);
|
const auto valueA = tryGetValue(node->GetBox(1), Value::Null);
|
||||||
const auto valueB = tryGetValue(node->GetBox(2), Value::Null);
|
const auto valueB = tryGetValue(node->GetBox(2), Value::Null);
|
||||||
const auto nodes = node->GetNodes(this);
|
value = Blend(node, valueA, valueB, alpha, AlphaBlendMode::Linear);
|
||||||
|
|
||||||
auto nodesA = static_cast<AnimGraphImpulse*>(valueA.AsPointer);
|
|
||||||
auto nodesB = static_cast<AnimGraphImpulse*>(valueB.AsPointer);
|
|
||||||
if (!ANIM_GRAPH_IS_VALID_PTR(valueA))
|
|
||||||
nodesA = GetEmptyNodes();
|
|
||||||
if (!ANIM_GRAPH_IS_VALID_PTR(valueB))
|
|
||||||
nodesB = GetEmptyNodes();
|
|
||||||
|
|
||||||
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
|
|
||||||
{
|
|
||||||
Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
|
|
||||||
}
|
|
||||||
Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion);
|
|
||||||
value = nodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1758,35 +1747,38 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
|||||||
// [2]: int Pose Count
|
// [2]: int Pose Count
|
||||||
// [3]: AlphaBlendMode Mode
|
// [3]: AlphaBlendMode Mode
|
||||||
|
|
||||||
// Prepare
|
|
||||||
auto& bucket = context.Data->State[node->BucketIndex].BlendPose;
|
auto& bucket = context.Data->State[node->BucketIndex].BlendPose;
|
||||||
const int32 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]);
|
const int16 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||||
const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||||
const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses);
|
const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses);
|
||||||
const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt;
|
const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt;
|
||||||
|
|
||||||
// Skip if nothing to blend
|
|
||||||
if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
|
if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Check if swap transition end points
|
||||||
|
if (bucket.PreviousBlendPoseIndex == poseIndex && bucket.BlendPoseIndex != poseIndex && bucket.TransitionPosition >= ANIM_GRAPH_BLEND_THRESHOLD)
|
||||||
|
{
|
||||||
|
bucket.TransitionPosition = blendDuration - bucket.TransitionPosition;
|
||||||
|
Swap(bucket.BlendPoseIndex, bucket.PreviousBlendPoseIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if transition is not active (first update, pose not changing or transition ended)
|
// Check if transition is not active (first update, pose not changing or transition ended)
|
||||||
bucket.TransitionPosition += context.DeltaTime;
|
bucket.TransitionPosition += context.DeltaTime;
|
||||||
|
bucket.BlendPoseIndex = poseIndex;
|
||||||
if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD)
|
if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD)
|
||||||
{
|
{
|
||||||
bucket.TransitionPosition = 0.0f;
|
bucket.TransitionPosition = 0.0f;
|
||||||
|
bucket.BlendPoseIndex = poseIndex;
|
||||||
bucket.PreviousBlendPoseIndex = poseIndex;
|
bucket.PreviousBlendPoseIndex = poseIndex;
|
||||||
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
|
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ASSERT(bucket.PreviousBlendPoseIndex >= 0 && bucket.PreviousBlendPoseIndex < poseCount);
|
|
||||||
|
|
||||||
// Blend two animations
|
// Blend two animations
|
||||||
{
|
{
|
||||||
const float alpha = bucket.TransitionPosition / blendDuration;
|
const float alpha = bucket.TransitionPosition / blendDuration;
|
||||||
const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null);
|
const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null);
|
||||||
const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
|
const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null);
|
||||||
value = Blend(node, valueA, valueB, alpha, mode);
|
value = Blend(node, valueA, valueB, alpha, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user