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.
Limitations
Resetting Properties
The Animancer v8.0 Test Package has a new solution to this problem which is explained on the
PlayableOutputRefresher
API page. The rest of this section should no longer be necessary when using that system and will be rewritten once Animancer v8.0 is released.
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.
There are two general workarounds for this issue, but unfortunately neither of them is particularly convenient:
Fully configure the playable graph on startup:
- Set
animancerComponent.Playable.KeepChildrenConnected = true
. - Call
animancerComponent.Layers[x].GetOrCreateState
for every animation the character might want to play. - Don't create or destroy any states after that.
Manually store and restore the values that would reset:
- Find everywhere your code does something that might connect or disconnect a
Playable
such as playing a new animation. - Before that code, store the values of all constraints that you want.
- After that code, call
animancerComponent.Animator.Rebind();
to force the required reset immediately. - 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 evaluates 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.