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)
|
||||
{
|
||||
bucket.BlendPose.TransitionPosition = 0.0f;
|
||||
bucket.BlendPose.BlendPoseIndex = -1;
|
||||
bucket.BlendPose.PreviousBlendPoseIndex = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +239,8 @@ public:
|
||||
struct BlendPoseBucket
|
||||
{
|
||||
float TransitionPosition;
|
||||
int32 PreviousBlendPoseIndex;
|
||||
int16 BlendPoseIndex;
|
||||
int16 PreviousBlendPoseIndex;
|
||||
};
|
||||
|
||||
struct StateMachineBucket
|
||||
|
||||
@@ -676,9 +676,12 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const
|
||||
if (!ANIM_GRAPH_IS_VALID_PTR(poseB))
|
||||
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++)
|
||||
{
|
||||
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);
|
||||
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 valueB = tryGetValue(node->GetBox(2), Value::Null);
|
||||
const auto nodes = node->GetNodes(this);
|
||||
|
||||
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;
|
||||
value = Blend(node, valueA, valueB, alpha, AlphaBlendMode::Linear);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1758,35 +1747,38 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
// [2]: int Pose Count
|
||||
// [3]: AlphaBlendMode Mode
|
||||
|
||||
// Prepare
|
||||
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 int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses);
|
||||
const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt;
|
||||
|
||||
// Skip if nothing to blend
|
||||
if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
|
||||
{
|
||||
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)
|
||||
bucket.TransitionPosition += context.DeltaTime;
|
||||
bucket.BlendPoseIndex = poseIndex;
|
||||
if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD)
|
||||
{
|
||||
bucket.TransitionPosition = 0.0f;
|
||||
bucket.BlendPoseIndex = poseIndex;
|
||||
bucket.PreviousBlendPoseIndex = poseIndex;
|
||||
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
|
||||
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null);
|
||||
break;
|
||||
}
|
||||
ASSERT(bucket.PreviousBlendPoseIndex >= 0 && bucket.PreviousBlendPoseIndex < poseCount);
|
||||
|
||||
// Blend two animations
|
||||
{
|
||||
const float alpha = bucket.TransitionPosition / blendDuration;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user