Description

When BlendRootMotionBasedOnRootBone is false, the LayeredBlendPerBone is aggregating root motion of the child poses ontop of the base pose root motion.  (ie. if the first child pose's blend weight is 1, you get 100% root motion from the first child but also 100% from the base pose). 

The expected behaviour is that the root motion of the child poses should instead be blended with the base pose.  (ie. if the first child pose's blend weight is 1, you get 100% of root motion from the first child and 0% from the base pose).

The code responsible for this is:

float RootMotionWeight = 0.f;
const float RootMotionClearWeight = bBlendRootMotionBasedOnRootBone ? 0.f : 1.f;

if (IsLODEnabled(Context.AnimInstanceProxy))
{
    GetEvaluateGraphExposedInputs().Execute(Context);

    for (int32 ChildIndex = 0; ChildIndex < BlendPoses.Num(); ++ChildIndex)
    {
       const float ChildWeight = BlendWeights[ChildIndex];
       if (FAnimWeight::IsRelevant(ChildWeight))
       {
          if (bHasRelevantPoses == false)
          {
             // Update cached data now we know we might be valid
             UpdateCachedBoneData(Context.AnimInstanceProxy->GetRequiredBones(), Context.AnimInstanceProxy->GetSkeleton());

             // Update weights
             FAnimationRuntime::UpdateDesiredBoneWeight(DesiredBoneBlendWeights, CurrentBoneBlendWeights, BlendWeights);
             bHasRelevantPoses = true;

             if(bBlendRootMotionBasedOnRootBone && !CurrentBoneBlendWeights.IsEmpty())
             {
                const float NewRootMotionWeight = CurrentBoneBlendWeights[0].BlendWeight;
                if(NewRootMotionWeight > ZERO_ANIMWEIGHT_THRESH)
                {
                   RootMotionWeight = NewRootMotionWeight;
                   RootMotionBlendPose = CurrentBoneBlendWeights[0].SourceIndex;
                }
             }
          }

          const float ThisPoseRootMotionWeight = (ChildIndex == RootMotionBlendPose) ? RootMotionWeight : RootMotionClearWeight;
          BlendPoses[ChildIndex].Update(Context.FractionalWeightAndRootMotion(ChildWeight, ThisPoseRootMotionWeight));
       }
    }
}

// initialize children
const float BaseRootMotionWeight = 1.f - RootMotionWeight;

if (BaseRootMotionWeight < ZERO_ANIMWEIGHT_THRESH)
{
    BasePose.Update(Context.FractionalWeightAndRootMotion(1.f, BaseRootMotionWeight));
}
else
{
    BasePose.Update(Context);
} 

Because 
bBlendRootMotionBasedOnRootBone is false in this setup, we never set RootMotionWeight so it is always zero.  Meaning that BaseRootMotionWeight (which is passed as the root motion weight into the BasePose pose link) is always 1 so we always get 100% of the root motion from that pose.
If/when we fix this we should be careful of any behaviour change for users who may be relying on the broken behaviour.

Steps to Reproduce
  1. Open the attached project (gdrive link: [Link Removed])
  2. Open Untitled level
  3. Simulate and note how both meshes move at the same rate
    1. The background mesh is running a ABP with a single run animation
    2. The foreground mesh is running an ABP using the layered blend node to blend a run onto an idle.  The blend mask is weighted so all bones are 100% from the base pose (the idle).  Because BlendRootMotionBasedOnRootBone on the layered blend node is false, the root motion is blended using the blend weight input to the node which is weighted 100% to Blend Poses 0 (the run).  So the root motion appears to be only taken from the run.
  4. Stop simulating and edit ABP_00570572
  5. Switch Base Pose to the Fwd animation
  6. Return to the level viewport and simulate
    1. Expected behaviour: The root motion is as previously, taken 100% from Blend Poses 0 (the run animation) so the mesh translates at the same speed as previously (same speed as the background mesh)
    2. Actual behaviour: The root motion is now even faster because the root motion of Base Pose is being added to Blend Poses 0

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-187223 in the post.

0
Login to Vote

Won't Fix
CreatedMay 27, 2023
ResolvedJun 1, 2023
UpdatedJun 5, 2023
View Jira Issue