Fix blending nested animations to properly handle it per-node

#2416
This commit is contained in:
Wojtek Figat
2024-04-16 23:25:37 +02:00
parent 171fc276fb
commit c83b74c85d
2 changed files with 23 additions and 7 deletions

View File

@@ -25,7 +25,7 @@ namespace
{
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{
nodes->Nodes[i].Orientation.Normalize();
nodes->Nodes.Get()[i].Orientation.Normalize();
}
if (rootMotionMode != RootMotionExtraction::NoExtraction)
{
@@ -222,7 +222,7 @@ FORCE_INLINE void GetAnimSamplePos(bool loop, float length, float startTimePos,
prevPos = GetAnimPos(prevTimePos, startTimePos, loop, length);
}
void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* node, bool loop, float length, float pos, float prevPos, Animation* anim, float speed, float weight, ProcessAnimationMode mode)
void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode* node, bool loop, float length, float pos, float prevPos, Animation* anim, float speed, float weight, ProcessAnimationMode mode, BitArray<InlinedAllocation<8>>* usedNodes)
{
PROFILE_CPU_ASSET(anim);
@@ -240,9 +240,16 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
}
// Evaluate nested animations
bool hasNested = false;
BitArray<InlinedAllocation<8>> usedNodesThis;
if (anim->NestedAnims.Count() != 0)
{
if (usedNodes == nullptr)
{
// Per-channel bit to indicate which channels were used by nested
usedNodesThis.Resize(nodes->Nodes.Count());
usedNodes = &usedNodesThis;
}
for (auto& e : anim->NestedAnims)
{
const auto& nestedAnim = e.Second;
@@ -262,8 +269,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
nestedAnimPrevPos = nestedAnimPrevPos * frameRateMatchScale;
GetAnimSamplePos(nestedAnim.Loop, nestedAnimLength, nestedAnim.StartTime, nestedAnimPrevPos, nestedAnimPos, nestedAnimPos, nestedAnimPrevPos);
ProcessAnimation(nodes, node, true, nestedAnimLength, nestedAnimPos, nestedAnimPrevPos, nestedAnim.Anim, 1.0f, weight, mode);
hasNested = true;
ProcessAnimation(nodes, node, true, nestedAnimLength, nestedAnimPos, nestedAnimPrevPos, nestedAnim.Anim, 1.0f, weight, mode, usedNodes);
}
}
}
@@ -295,6 +301,15 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
{
RetargetSkeletonNode(mapping.SourceSkeleton->Skeleton, mapping.TargetSkeleton->Skeleton, sourceMapping, srcNode, i);
}
// Mark node as used
if (usedNodes)
usedNodes->Set(i, true);
}
else if (usedNodes && usedNodes != &usedNodesThis)
{
// Skip for nested animations so other one or top-level anim will update remaining nodes
continue;
}
// Blend node
@@ -316,7 +331,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
dstNode.Scale = srcNode.Scale * weight;
dstNode.Orientation = srcNode.Orientation * weight;
}
else if (!hasNested)
else
{
dstNode = srcNode;
}