All Classes Namespaces Functions Variables Enumerations Properties Pages
Aim IK

AimIK solver is a modification of the CCD algorithm that rotates a hierarchy of bones to make a child Transform of that hierarchy aim at a target. It differs from the basic built-in Animator.SetLookAtPosition or the LookAtIK functionality, because it is able to accurately aim transforms that are not aligned to the main axis of the hierarchy.

AimIK can produce very stabile and natural looking retargeting of character animation, it hence has great potential for use in weapon aiming systems. With AimIK we are able to offset a single forward aiming pose or animation to aim at targets even almost behind the character. It is only the Quaternion singularity point at 180 degrees offset, where the solver can not know which way to turn the spine. Just like LookAtIK, AimIK provides a clampWeight property to avoid problems with that singularity issue.

AimIK also works with rotation limits, however it is more prone to get jammed than other constrained solvers, should the chain be heavily constrained.

Aim provides high accuracy at a very good speed, still it is necessary to keep in mind to maintain the target position at a safe distance from the aiming Transform. If distance to the target position is less than distance to the aiming Transform, the solver will try to roll in on itself and might be unable to produce a finite result.

AimIK.png
The AimIK solver in action


Getting started:


Component variables:


Solver variables:

AimIKComponent.png


Script References:


Changing the aiming target:

public AimIK aimIK;
void LateUpdate () {
aimIK.solver.IKPosition = something;
}


Using the Pole:

The polePosition can be helpful when making weapon aiming setups. Let's say we have a gun that's local Z axis is facing towards its barrel and local Y axis is facing up. In this case we have to set AimIK "Axis" to (0, 0, 1) and "Pole Axis" to (0, 1, 0). If we now play the scene and set "Weight" and "Pole Weight" to 1, we will have 2 handles, one for the aiming target and the other for twisting the gun and the body of the character.

Adjusting the Pole by script:

public AimIK aimIK;
void LateUpdate () {
aimIK.solver.polePosition = something;
aimIK.solver.poleWeight = 1f;
}


Changing the Aim Transform:

public AimIK aimIK;
void LateUpdate () {
aimIK.solver.transform = something;
aimIK.solver.axis = localAxisOfTheTransformToAimAtTheTarget;
}


Adding AimIK in runtime:


Changing AimIK bone hierarchy in runtime:

public AimIK aimIK;
public Transform[] newBones;
void Change() {
aimIK.solver.SetChain(newBones, aim.transform);
}


Using AimIK with Rotation Limits:

It is sometimes necessary to limit the effect of AimIK on one of the bones in its chain. Usually when you wish to use the elbow joint in the process of aiming a single handed weapon or when you wish to limit the rotation of a spine bone to twisting only. If you just added the RotationLimit component to the bone, it would also interfere with the animation (keep the spine stiff), not just the IK. You can make the RotationLimit only have an effect on the AimIK by defaulting its rotation each frame before AimIK solves:

public AimIK aimIK;
void LateUpdate() {
// Set current animated localRotation as default local rotation for the rotation limits so they will not interfere with the animation, but only the IK
for (int i = 0; i < aimIK.solver.bones.Length; i++) {
if (aimIK.solver.bones[i].rotationLimit != null) {
aimIK.solver.bones[i].rotationLimit.SetDefaultLocalRotation();
}
}
}

Please note that each RotationLimit decreases the probability of the solver smoothly reaching its target.
Since FinalIK 0.4 introduced the polePosition and poleWeight, using Rotation Limits on characters can in most cases be avoided by using the pole to keep the body upright.


Bone weights

Each bone in the "Bones" has a weight parameter. It determines how much proportionally is a bone used in the solving process. Fox example if you do not wish a certain spine bone to bend too much, you can just decrease its weight.


Aiming 2-handed weapons:

When aiming 2-handed weapons, we can use only the spine bones (common parents for both hands) in the AimIK bone hierarchy. If we used the arm bones, the other hand would lose contact with the object. Sometimes using just the spine bones is not enough though, as the spine would bend exessively and the character would end up in unnatural poses. We can solve this problem, by adding some of the arm bones (the arm that is holding the object) to AimIK and then use FullBodyBipedIK or LimbIK to put the other hand back on its place after AimIK is done. Take a look at this tutorial video to see how it could be done.


Redirecting animation:

AimIK is perfect for keeping objects steadily aimed at the target. Sometimes those objects have a lot of swinging motion in the animation, like swinging a sword for example, and it is not good to use AimIK to keep the sword oriented at a certain position during that swing. It would keep the sword orientation fixed by bending the rest of the hierarchy and that would interfere with the animation in an unwanted way. It is still possible to use AimIK to redirect swinging animations like swordplay or punching, take a look at this tutorial video to see how it could be done.


Recoil/reload animations while aiming:

While AimIK weight is 1, the solver will maintain the weapon oriented at the target at all times. This might not be the desired behaviour while playing a recoil or reloading animation. We can dynamically change the Axis of AimIK to overcome this issue.

void LateUpdate() {
aimIK.solver.axis = aimIK.solver.transform.InverseTransformDirection(character.forward);
}

That line is telling AimIK that whatever the direction of the weapon in the animation, it is the default forward aiming direction. "Character.forward" is the direction that the weapon is aimed at (keep it in character space so the effect rotates with the character) in the normal aiming animation without any recoil, so If you were currently playing an "aim right" animation, you should set it to "character.right" instead.