The most common form of animation uses Forward Kinematics where each bone is given a specific rotation which it adds to the rotation of its parent. So you rotate the shoulder and the elbow moves accordingly because it is a child of the shoulder. You rotate the elbow and the hand moves accordingly. And so on.
But sometimes it is desirable to directly control the end point instead. With Inverse Kinematics, you specify the desired position of a hand or foot and the IK system figures out how to rotate the bones to get it there. This can be used to have a hand reach a specific point such as a door handle or adjusting the height of a foot to match the terrain.
Animancer allows you to use Unity's inbuilt Humanoid IK system in mostly the same way you would with Mecanim. The main difference is that you enable it by setting AnimancerNode.ApplyFootIK
or AnimancerNode.ApplyAnimatorIK
on a state or layer instead of enabling it with toggles in an Animator Controller.
You can also enable/disable IK using the Context Menu Functions in the AnimancerComponent
Inspector for testing purposes (the setting will not be stored in the scene or prefab, so you will always need to enable Ik with a script to use it at runtime).
The Inverse Kinematics samples demonstrate the use of this feature.
IK Pass
The IK Pass causes Unity to call the OnAnimatorIK(int layerIndex)
method every frame in any scripts attached to the same object as the Animator
.
void EnableIKPass(AnimancerComponent animancer, AnimationClip clip)
{
// Enable IK Pass for all states:
animancer.Playable.ApplyAnimatorIK = true;
// Enable IK Pass for all states on a specific layer:
animancer.Layers[0].ApplyAnimatorIK = true;
// Enable IK Pass for a specific state (and any children if it is a mixer):
AnimancerState state = animancer.States.GetOrCreate(clip);
state.ApplyAnimatorIK = true;
}
This is equivalent to the IK Pass
toggle in an Animator Controller layer, except that due to limitations in the Playables API the layerIndex
Unity passes into OnAnimatorIK
will always be zero:
By default, states will automatically be given the IK Pass setting from their parent when it is assigned (such as when creating a new state or moving it to a different layer). This can be prevented by setting AnimancerNode.ApplyParentAnimatorIK = false;
before changing the parent.
Foot IK
Foot IK allows Unity to make the character's feet more closely match the original animation's positions after retargeting it from the animation's rig to the model's rig. This can help reduce foot sliding caused by differing rig proportions, but it also often has undesirable results so it should be selected on a case by case basis.
void EnableFootIK(AnimancerComponent animancer, AnimationClip clip)
{
// Enable Foot IK for all states:
animancer.Playable.ApplyFootIK = true;
// Enable Foot IK for all states on a specific layer:
animancer.Layers[0].ApplyFootIK = true;
// Enable Foot IK for a specific state (and any children if it is a mixer):
AnimancerState state = animancer.States.GetOrCreate(clip);
state.ApplyFootIK = true;
}
This is equivalent to the Foot IK
toggle in an Animator Controller state:
By default, states will automatically be given the Foot IK setting from their parent when it is assigned (such as when creating a new state or moving it to a different layer). This can be prevented by setting AnimancerNode.ApplyParentFootIK = false;
before changing the parent.
Animated Properties
The AnimatedBool
, AnimatedFloat
, and AnimatedInt
classes allow you to access the values of custom curves in your animations at runtime. This is often used to control the weight of the IK so that some parts of the animation use more IK than others. 0 means the limb will be fully controlled by the animation while 1 means the IK system will be fully in control, with anything inbetween giving a proportional amount of control.
[SerializeField] private AnimancerComponent _Animancer;
private AnimatedFloat _FootWeights;
protected virtual void Awake()
{
_Animancer.Layers[0].ApplyAnimatorIK = true;
_FootWeights = new AnimatedFloat(_Animancer, "LeftFootIK", "RightFootIK");
}
protected virtual void OnAnimatorIK(int layerIndex)
{
// [0] is the first name we passed into the constructor:
float currentLeftFootWeight = _FootWeights[0];
// [1] is the second name we passed into the constructor:
float currentRightFootWeight = _FootWeights[1];
...
}
The Uneven Ground sample demonstrates the use of this feature in more detail.
Adding custom curves to an animation is done differently depending on where it's located:
- If the animation is imported as part of a model, you can add custom curves in the Import Settings -> Animation Tab -> Curves (foldout near the bottom).
- Otherwise you can add custom curves using the Animation window.
In an Animator Controller, you can access a custom curve by creating a Float Parameter with the same name as the curve. Then it will automatically update that parameter every frame with the value of the curve at the current time so you can access it in a script using animator.GetFloat("Parameter Name")
.
Exposed Curves
Before Animated Properties were implemented, previous versions of Animancer allowed access to custom curves by using using an ExposedCurve
class to extract a curve from the AnimationClip
in the Unity Editor and serialize it separately so that it can be accessed directly at runtime. That class can now be downloaded from here and using it is fairly straightforward:
- Create an
ExposedCurve
using Assets/Create/Animancer/Exposed Curve. - Assign the
AnimationClip
containing the curve and enter theProperty Name
of the curve. - Any future changes to the original curve in the
AnimationClip
will automatically be retrieved by theExposedCurve
. Unfortunately it is not currently possible to edit the curve using theExposedCurve
Inspector. You need to edit the curve in the Animation window or the model import settings. - Reference that asset in your script and evaluate it during
OnAnimatorIK
to determine how much weight to give the IK system during each frame:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private ExposedCurve _RightFootWeight;
protected virtual void OnAnimatorIK(int layerIndex)
{
float currentWeight = _RightFootWeight.Evaluate(_Animancer);
...
}
Note that an ExposedCurve
can only evaluate the target curve from a single animation where an Animated Property will automatically Blend the value according to all the animations currently playing.