Accessing the input pose to anim graph from anim instance code

Hi,

What is the best way to access the input pose to my anim graph from my anim instance code? Is it even possible?

To explain the use-case a bit, I am working on an anim instance for IK and my anim graph needs to occasionally update IK bones too, so I cannot use my IK bones for tracing in code as it would create a feedback loop. Ideally, I would like to be able to access the input pose in code so this feedback loop can be avoided.

Many thanks,

Maryam

Hi Maryam,

Can you give me a bit more information on your setup? I’d to know a bit more about your setup and what you want to achieve with it to give more specific advice.

In general though, the evaluation of the graph starts from FAnimInstanceProxy::EvaluateAnimation_WithRoot and the pose that’s generated is stored in the pose context that’s passed into that method. That pose is then passed through each node in the graph. But the pose doesn’t have any transform data in it to start with; it’s all generated as the nodes are being evaluated.

There is also the pose data stored on the mesh (USkinnedMeshComponent::GetEditableComponentSpaceTransforms and USkeletalMeshComponent::GetBoneSpaceTransforms), which are where we eventually write the transforms for the current frame after the graph evaluation, but those aren’t safe to access during the evaluation of the graph. (And they are effectively the last frame’s transforms until the evaluation has completed.)

Is the custom anim instance going to be used as a linked anim graph where you pass a transform buffer as an input into the sub-graph? If that’s the case, you may be able to grab the transforms that are input to the linked graph node.

Thanks,

Euan

Hi Euan,

Thanks for getting back to me so quickly!

In my setup, I have an anim instance and I trace down the feet to find my IK targets. In my anim graph, I pass on these targets to a control rig, in which I only have an FBIK node to solve for a new pose. But because I am tracing down feet bones (and not IK bones, because other systems change IK bones and they are not an accurate representation of feet position) and then update them using FBIK, I get a feedback loop because SkeletalMeshComponent->GetBoneTransform gives me the evaluated pose from last frame and not the input pose to the anim graph.

To answer your question, my IK graph is indeed a linked anim graph. I am not sure what you mean by whether I pass a transform buffer, but it receives the Source Pose.

I have a couple of questions:

1- Is it more performant to have bone traces inside anim instance rather than control rig?

2- You mentioned that there might be a way to grab the transforms that are input to my linked anim graph. What would that be?

Many thanks,

Maryam

Thanks for the extra info. This is a reasonably common issue to run into since you can’t query bones individually and operate on them within the anim graph.

Typically, we recommend performing all of the work within a custom anim graph node that calculates the targets and performs the IK solve. Each anim graph node has access to update-to-date bone transforms for the point in the graph that it lives in via the Evaluate_AnyThread (or EvaluateSkeletalControl_AnyThread) method. For instance, you can see in FAnimNode_FootPlacement::EvaluateSkeletalControl_AnyThread how ProcessFootAlignment gets the position of the feet and performs the raycast. We then use the results later for the custom solve.

If you want to go down this route, but you still want to leverage the FBIK solve, you could do this via an IK rig rather than a control rig. You’d author the IK rig with goals on the feet, and set up the FBIK solver. Then, in your custom node, you’d get the IK Rig, set up the goals based on the information you received from the raycast, and then run the solve on the rig. FAnimNode_IKRig::Evaluate_AnyThread shows how you would se tup the goals and run the solve. (You can’t just use the FAnimNode_IKRig node on its own in this case since you’re back to the original problem where you need to get the target positions from the current frame’s transforms.)

Having said all of that, Control Rig is designed to do exactly what you want (per-bone manipulation of the pose). So there wouldn’t be an issue with implementing all of this logic within a control rig. This is the direction we’re heading in with future sample work, rather than the various animation warping nodes we’ve used previously.

Whether there’s a performance impact of the control rig approach depends on your overall setup. If you already have a control rig within the anim graph, and you’re just moving the work into the control rig, it’s not going to have much, if any, effect (even if you have a number of nodes doing the work in the control rig since the VM is much faster than the regular anim bp VM). However, if you’re adding a control rig specifically to do this work, that would have some impact on your performance (although this is somewhat better in 5.6 than it was previously).

Lastly, there is a hybrid option where you use an animation node to calculate the target locations and pass them into a control rig. The best way to do this would be via animation attributes. Animation attributes are passed around the nodes in the anim graph via the FPoseContext object that’s passed into the EvaluateAnyThread functions in the same way that the bone transforms are. You would do something like this in your custom node’s evaluate method (I haven’t tried compiling this code):

void FAnimNode_CustomNode::Evaluate_AnyThread(FPoseContext& Output)
{
    // do raycast to get target positions
    // ...
 
    const UE::Anim::FAttributeId LeftFootTargetAttributeId(TEXT("LeftFootTarget"), FCompactPoseBoneIndex(0));
    if (FVectorAnimationAttribute* LeftFootTargetAttribute = Output.CustomAttributes.FindOrAdd<FVectorAnimationAttribute>(LeftFootTargetAttributeId))
    {
        LeftFootTargetAttribute->Value = LeftFootTargetPos;
    }
}

And then in your control rig, you can use the GetAnimationAttribute node to retrieve the attribute value and use that as a target for your FBIK solve.

Hopefully that gives you some options that will work for your situation.

Great, good to hear that was helpful!

Thank you very much for the extensive info and examples, Euan. This definitely clarifies things for me and helps a lot!