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.
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-187223 in the post.
0 |
Component | UE - Anim - Runtime |
---|
Created | May 27, 2023 |
---|---|
Resolved | Jun 1, 2023 |
Updated | Jun 5, 2023 |