Animation Rigging

Unity's Animation Rigging package allows you to set up rigs that dynamically modify your animations with things like Multi-Parent Constraints and Inverse Kinematics (which works on both Generic and Humanoid Rigs where Unity's inbuilt IK system only works on Humanoids).

The official Working with Animation Rigging tutorial explains how to use it. Using it with Animancer is no different from using it with Animator Controllers.

Click here to see some of its features.

Damped Transform

Multi Parent Constraint

Inverse Kinematics

Limitations

Background

The way the Animation Rigging system reads properties like the Weight of its constraint components causes them to be treated like animated properties, meaning that calling Animator.Rebind will reset those properties to their starting values.

Unfortunately, Animator.Rebind gets called every time a Playable is connected or disconnected which happens frequently in Animancer depending on the AnimancerPlayable.KeepChildrenConnected property:

KeepChildrenConnected Event Common Example
true
Default for Generic Rigs
A state's layer is set. Playing an animation that hasn't been played on that character yet will create a new state for it and connect that state to a layer (usually the default base layer).
false
Default for Humanoid Rigs
A state's layer is set or its Weight changes to or from 0. Playing an animation sets its Weight to 1 (or fades it in) which connects it to its layer and stopping an animation sets its Weight to 0 which disconnects it from its layer.

This isn't a problem for Animator Controllers because they simply don't allow their structure to be changed at runtime.

Workarounds

There are two general workarounds for this issue, but unfortunately neither of them is particularly convenient:

Fully configure the playable graph on startup:

  1. Set animancerComponent.Playable.KeepChildrenConnected = true.
  2. Call animancerComponent.Layers[x].GetOrCreateState for every animation the character might want to play.
  3. Don't create or destroy any states after that.

Manually store and restore the values that would reset:

  1. Find everywhere your code does something that might connect or disconnect a Playable such as playing a new animation.
  2. Before that code, store the values of all constraints that you want.
  3. After that code, call animancerComponent.Animator.Rebind(); to force the required reset immediately.
  4. Then apply the stored values back to the constraint components.

Generally, the first approach is much simpler to implement because you don't need to add additional code every time you play anything. In some cases that might not be feasible such as if you want to have different animations for each weapon like in the Weapons example so you might want to use a combination of both approaches: when equipping a new weapon you store the rigging values, configure its new animations, and reset the values so that you won't need to repeat the store and reset every time you play something.

IK Targets

The position and rotation of Target and Hint objects used by the Inverse Kinematics system from the Animation Rigging package are affected by the same resetting effect explained above, but fortunately it can be avoided by ensuring those objects are not children of the character's Animator component. The Hierarchy should look something like this (the object names list their components):

Paused Graph

Normally, Animancer creates a PlayableGraph and the Animation Rigging system creates another one which reads its inputs from the previous one. This allows it to avoid interfering with the main animation system so it can work the same regardless of whether the primary graph is managed by an Animator Controller or Animancer or any other system that uses the Playables API.

Unfortunately, manually calling PlayableGraph.Evaluate (like in the Update Rate example) only evluates that graph on its own and there doesn't seem to be any way to make them both update in sequence as they would during a regular animation update. This causes the Animation Rigging system to completely fail if you try to manually evaluate the graph.

This can be solved by initializing Animancer to use the same PlayableGraph as the Animation Rigging system with a script like this:

using Animancer;
using UnityEngine;
using UnityEngine.Animations.Rigging;

[DefaultExecutionOrder(1000)]// Awake after the RigBuilder creates its PlayableGraph.
public sealed class AnimancerUseRiggingGraph : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private RigBuilder _RigBuilder;

    private void Awake()
    {
        var playable = AnimancerPlayable.Create(_RigBuilder.graph);
        _Animancer.InitializePlayable(playable);
    }
}

Then you can simply call _Animancer.Evaluate() normally and it will evaluate both Animancer and the Animation Rigging system properly.