Skeletal Control uses a stale transform if actor transform changed

In an animation blueprint, if the actor transform is changed in the “Update Animation” event, the skeletal control “Transform (modify) Bone” will not set the correct bone transform if it is set to use world space coordinates.

I did some debugging on this and found that when the engine calls
FAnimNode_ModifyBone::EvaluateSkeletalControl_AnyThread(),
The FAnimInstanceProxy struct that is passed in contains stale data. The component space transform is incorrect (out of date), which causes the bone transform to be set to the wrong value if the passed in transform is in world space.

Excerpt from Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_ModifyBone.cpp here:

It is possible to workaround the problem by changing the ModifyBone skeletal control to use component space and computing the correct transform manually in the UpdateAnimation event.

I have a small project (blueprint only) which demonstrates the issue, but it is ~20MB and this site only allows 5MB or less for an attachment.

Note that this issue is not limited to the Modify Bone skeletal control, it seems to affect all skeletal controls.

Update: link to repro project:
[SkelControlBug.zip - Google Drive][2]

Update: bug also occurs with 4.18.1

Hi,

If you can post a link to your project in something like Google Drive, Dropbox, or send it to me here, as well as the repro steps that you are taking I can take a look at the issue.

-Thank you

Thanks for taking a look!
Here is the link:

https://drive.google.com/open?id=1rZtlRG2_r9eGVtAsd9PY6do6TiHtOURE

It is a blueprint only project, designed specifically to highlight the issue. Press NUM 1 key to see the broken case, NUM 2 to see the workaround case.

Hi,

Thank you for the example project. I’ve taken a look at your project and I was hoping to get more information on what you are trying to accomplish with it. In your Blueprints it looks like your Get Owning Actor has an odd reference. I posted a screenshot below of which one I’m referring to. If you can give me more details, I’ll take another look at it.

-Thank you

Basically what I’m trying to do is move the Actor transform without moving the skeleton.

So the “Get Owning Actor” node is just grabbing the Actor that contains the skeletal mesh, in this example, it’s the actor named “ThirdPerson_AnimBP” in the map. The actor’s transform is being changed in the “Update Animation” event, just prior to animation being evaluated. The new transform needs to be applied before the animation is evaluated, so that is why I’m changing it in the “Update Animation” event.

However, when the AnimGraph is evaluated, even though the root joint is being set to a constant world space transform in the AnimGraph, it isn’t staying fixed – as evidenced by him popping around.
It happens because the “Transform Bone” skeletal control in the animgraph (when set to use “World Space”) is using stale (previous frame) values for the component-space to world-space transform.

When the workaround is enabled, I use a “Transform Bone” skeletal control which is set to use component-space, so it doesn’t use the (bad) component-space to world-space transform.

Hi,

After taking another look at the provided project it appears to be working as intended. In the animation Blueprint you use the node get owner and the owner of the Blueprint is the Skeletal Mesh ThirdPerson_AnimBP. Setting the owning actor’s location would result in the skeletal mesh being moved as it is. If you can give me an example of how you want to use this/end goal, I can take another look at it.

-Thank you

Yes, the actor transform is being changed, but did you see the part in the AnimGraph of ThirdPerson_AnimBP where the root joint is being set to a constant value?

Again, the whole point of this is to be able to change the actor transform (i.e. the part you’ve identified in the event graph), WITHOUT moving the skeleton.

Hi,

In this case the skeletal mesh(mesh and skeleton) is the actor. Unless you are wanting to remove the skeleton from its mesh, which can’t be separated in this way. After taking another look at the Blueprints, it is working as intended.

-Thank you

The actor transform and the root bone of the skeleton are not the same thing. Since the skeletal mesh is the root component of this actor, the actor transform and the mesh component space are the same thing and can’t be separated. However, the root bone of the skeleton is another thing entirely.
Sure, most of the time, the root bone tracks the mesh component, but it doesn’t have to.

To see an example, look at the workaround case in the example project. You’ll see the mesh staying in one place, while the actor transform (visible with debug lines) moves around randomly. This proves that the actor transform and the root bone of the skeleton are 2 different things.

cc-wevr,

The system is working as intended.

Take a look at FAnimInstanceProxy::PreUpdate (assuming you have source code). You’ll notice that in that method we’ll cache off the ComponentTransform, ComponentRelativeTransform, and ActorTransform. This is also where we call the PreUpdate method for any nodes in the AnimGraph.

I would recommend not making changes to the Actor’s or Skeleton’s position (including the position of any Components between the Skeleton and the Root Component) in the Event Graph. Instead, you should be making them elsewhere (like in the Pawn / Character / Actor tick, or from some other Gameplay event).

The AnimBP Event Graph is primarily intended to only control Animation Related features. More specifically, for calculating and caching state from the Game Thread that will be needed for the Animation update (which may run in Worker Threads). It can also be used to handle Anim Notifies and Montages. If you need animation to drive motion, you should be using Root Motion in your animations.

Thanks,
Jon N.

I looked at FAnimInstanceProxy::PreUpdate. It is being called before the AnimBP event graph update. That is why any changes to the actor transform made in the event graph are delayed by 1 frame.

Originally I tried changing the actor transform in the Actor tick, however the Actor tick seems to be called AFTER the animation update. Here is a sample UE 4.18 project where the actor tick is changing the actor transform between 2 locations, while the AnimBP is fixing the root bone to the origin. There is a 1 frame glitch after each time the actor transform changes.

https://drive.google.com/open?id=1ZaJYhPw_-l98fDh9717LOWVm4oaPJsYy

Is there any virtual function on UAnimInstance that I can override in a subclass to insert code before the FAnimInstanceProxy::PreUpdate is called? Unfortunately, UAnimInstance::PreUpdateAnimation() is not virtual. Nor is UAnimInstance::UpdateAnimation().
UAnimInstance::NativeUpdateAnimation() is virtual, but it is called after the PreUpdate.

After Speaking with Jon. N:

I looked at FAnimInstanceProxy::PreUpdate. It is being called before the AnimBP event graph update. That is why any changes to the actor transform made in the event graph are delayed by 1 frame.

It’s intended that PreUpdate is called before Update.

Is there any virtual function on UAnimInstance that I can override in a subclass to insert code before the FAnimInstanceProxy::PreUpdate is called?

FAnimInstanceProxy::PreUpdate itself is a virtual function. That means you could always do something like this:

void FMyAnimInstanceProxy::PreUpdate(UAnimInstance* AnimInstance) override
{
    AActor* MyActor = AnimInstance->GetOwningActor();
    // Do motion stuff.
    
    // Call the Super PreUpdate stuff. 
    Super::PreUpdate(AnimInstance);
}

Originally I tried changing the actor transform in the Actor tick, however the Actor tick seems to be called AFTER the animation update.

UAnimInstance::UpdateAnimations is called from USkeletalMeshComponent::TickAnimation which is ultimately called from USkinnedMeshComponent::TickComponent.

Both Actor and ActorComponent tick functions are run by the TaskGraph. This means a cleaner alternative would just be adding a TickDependency on the SkeletalMeshComponent to the Actor.

AMyActor::PostInitializeComponents() override
{
    Super::PostInitializeComponents();
    SkelMeshComponent->PrimaryComponentTick.AddPrerequisite(this, PrimaryActorTick);
}

This is a common thing to do. For example, ACharacter::PostInitializeComponents forces it’s Mesh component to tick after its CharacterMovementComponent for exactly the same reason (e.g., to make sure movement has occurred before animation).

There’s even a convenience method on UActorComponent (and AActor) called AddTickPrerequisiteActor.

-Thank you

I tried adding the Tick prerequisite as suggested and that works great. That’s just what I needed.
Thanks!