[UE 5.8] Orientation Warping's root rotation skips bones already cached in component space - one-frame body snap

Summary

Orientation Warping (AnimationWarping plugin) turns the body by rotating the ROOT bone through FCSPose::SetComponentSpaceTransform, which does not invalidate the root’s children. So the root rotation only carries descendants whose component-space transform is not yet cached in that pose. When an earlier node in the same component-space chain (e.g. Stride Warping or Steering) has already evaluated the pelvis / spine, those bones do not follow the warp on that frame, and the body steps back by the root share of the warp angle (angle x DistributedBoneOrientationAlpha) in a single frame. Seen as a 17-27 degree one-frame pelvis / spine / head snap on starts from idle in a GASP-style locomotion graph.

What Type of Bug are you experiencing?

Animation

Steps to Reproduce

  1. In an Animation Blueprint, build a per-sample component-space chain like the Game Animation Sample’s locomotion: Steering and/or Stride Warping, then Orientation Warping (with spine bones, DistributedBoneOrientationAlpha > 0), all in the same component-space section.
  2. Drive a start from idle into a 90 or 180 degree direction change, so Orientation Warping applies a large angle while the start blends in.
  3. Record the pelvis / spine_03 / head component-space yaw per frame relative to the root (or watch the torso and head).
  4. For comparison, insert a Component To Local node followed by a Local To Component node immediately before Orientation Warping, and repeat step 2.

Code reference (UE 5.8): AnimNode_OrientationWarping.cpp, EvaluateSkeletalControl_AnyThread: “Rotate Root Bone first, as that cheaply rotates the whole pose with one transformation” calls Output.Pose.SetComponentSpaceTransform(RootBoneIndex, …). BonePose.h, FCSPose::SetComponentSpaceTransform sets only Pose[BoneIndex] and ComponentSpaceFlags[BoneIndex] = 1; children’s flags are not cleared.

Expected Result

The root rotation applied by Orientation Warping carries the whole pose every frame, as its comment says, regardless of which bones an earlier node has already evaluated in component space. The warp angle changes smoothly, so the body should turn smoothly, with no one-frame step.

Observed Result

For about 19 frames the pelvis / spine follow the root’s rotation. On the frame an earlier node has computed their component-space transforms, they stay put and the body drops back by the whole root share at once.

  • Measured one-frame steps: idle → 180 start, head 26.7 deg / spine 24.3 deg; idle → 90 start, pelvis 17.1 deg.
  • With the warp’s alpha forced to 0 the step falls to the clip’s own (3.5 / 6.5 deg).
  • The warp’s own internal angle is smooth throughout, so the step comes purely from which bones the root rotation reaches.
  • With the Component To Local + Local To Component pair before the node, the step disappears: idle → 180 26.7 → 3.6 deg, idle → 90 17.1 → 4.7 deg; a straight start is unchanged (3.9).

Affects Versions

5.8

Platform(s)

Windows

Additional Notes

Platform-independent (pose code); seen on Windows and Linux. Workaround in use: a Component To Local + Local To Component pair right before Orientation Warping, so it always receives a pose with no cached component-space transforms below the root.

Suggested fix: when Orientation Warping rotates the root, also reach every descendant whose component-space transform is already cached (invalidate their flags, or rotate their cached transforms too), so “rotates the whole pose” holds. Alternatively, document that the node needs a pose with no cached component-space transforms below the root.