Earlier this year we introduced the Animation Rigging package. Our initial goal was to provide a suite of constraints that can be used to create different rigs to alter or modify your animation at runtime.
We've been exploring many of the possibilities that this package offers, pushing the boundaries between runtime and authoring. This article sheds light on some of our recent Animation Rigging experiments. PLEASE be aware that the state machine in the following example is experimental, not necessarily representative of a viable production example. We are simply exploring how a technical animator might author constraint interactions with a state machine without needing to write any code.
We hope this article will inspire you to explore and discover new ways to address the animation challenges you face every day. To build a viable and complete animation solution, we believe it's in our best interest to find out what you discovered and what you need.
This blog will focus on three types of component: Rig Builder, Rig, and various kinds of Constraints. If you're not already familiar with these, we suggest you consult our previous blog post on Animation Rigging.
In order to follow along more easily, you might want to download the project we're referencing here.
The first thing we decided we needed was to find a way to make it so that the rig constraints can be animated within the context of an existing Animator (state machine logic with read-only clips), without any direct user code intervention. We’ve found a solution in the state machine (Animator) Layers.
To properly synchronize the activation of the rigs and constraints with the read-only clips in the existing state machine, we leveraged the Animator state machine Layers.
Using Layers and the “Sync” functionality, we can add rig activation/deactivation clips to any state in our existing locomotion state machine.
Using the animation window we’ve created several animation clips (stored in the *Rig Layers) that animate the rigs and constraint properties. Again, we are simply animating Weight and Source Weight properties of different rigs and constraints.
Note that we also used the “Player” script to activate or deactivate some Weight Layer properties for an alternative hang grip. This is a slider on the Player script that changes the handgrip pose.
The Rig Builder component provides you with the Rig Layers you need to re-order and ensure the desired evaluation and solving results between rigs/rig parts. This provides flexibility for rig combinations and the ordering of solves. For instance, let's see what happens if we deliberately misorder the Shoulder Offset Rig in our ninja example.
By moving the Shoulder Correction Rig to the bottom of the Rig Builder evaluation stack, we broke the expected solving.
With the Shoulder Correction Rig at the top of the Rig Builder evaluation stack we obtain the proper solving behavior.
In the top image, Shoulder Offset is placed at the bottom of the stack, resulting in a misalignment of the hands. With correct ordering, the shoulder is solved before the rest of the arm, so the hand can correctly grip the pistol. We can then adjust the Pistol handgrip using the correction provided by the RightArm IK to solve for the UpperBody Rig.
Note: The following descriptions of the rig and constraints setup do not necessarily match the order in which it is represented in the image above.
The Shoulder Correction rig is used in combination with the Right Arm Two Bone IK constraint to correct the posing of the Right Shoulder bone to match the pose delta between the Assault Rifle Idle animation and the Pistol idle Pose.
We used the Override Transform in Pivot mode on the RightShoulder (Transform) to enforce additive rotational values on Y and Z transforms. Notice that we’re only affecting Rotation by setting the Position Weight to 0.
Check out the Hips Constraint GameObject and its children. Using the Hips Ctrl in pivot mode as a source in an Override Transform to affect the Hips bones allows us to offset the entire ninja hierarchy. Then we use a combination of constraints (Multi-Aim & Override Transform) to create an upper body aim rig that affects the spine section as well as the hips. Setting different aim weight constraint values (see, in each case, the Multi Aim Constraint > Source Objects for spine 0.35, chest 0.5, upper chest 0.75, and head 1.0) affects the distribution of rotation across all spine effectors. All of these source the Target GameObject to different degrees to create the effect.
The Weapon Rig GameObject uses the Override Transform to allow us to hijack the Weapon Bone animation stream and redirect it using a source object (Weapon Ctrl).
We then use the same source object as a reference object in a Multi-referential constraint to gain a multi-pivot manipulation. Try playing with the values under Multi Referential Constraint > Driving to see this in action.
The Two Bone IK provides the IK solving on both skeleton arms. Multi-Parent Constraints are used to attach the RHIK & LHIK Effectors to the Weapon_Bone child IK Target Game Objects (AR_LHIK_Target & AR_RHIK_Target).
To convert the original Idle Animation to a Pistol Stance we use a set of animation rigging constraints. We offset data coming from the Pistol Ctrl effector to the Weapon Bone with the help of the Override Transform using the Pivot mode option. Then, we leverage the Maintain Offset in Position & Rotation of the Multi-Parent constraint to cancel out the global coordinate discrepancy between the source (Weapon Bone) and the target (Pistol Offset) game object.
To attach the Assault Rifle (AR) and Pistol skeletons to different anchor point, we take advantage of the multi-source functionality of the multi-parent constraint.
The Assault Rifle Attach Rig makes good use of the multi-source functionality of the Multi-Parent Constraint. When AR_Holster source is set to 1 (and Weapon_Bone source to 0) the AR_Grip_Bone attaches itself to the AR_Holster.
If we want the Assault Rifle (AR_Grip_Bone) to follow the Weapon_Bone we simply set the Weapon_Bone source to 1 (and AR_Holster source to 0).
Note that we can keyframe most of the properties of any constraint, and in this case each multi-parent source weight, to obtain the desired result.
This is key. As these new animation clips will then be used in a state of a “synced” Animator controller Layer to enforce certain rig states in specific states of the existing locomotion (or other) state machine.
The following example demonstrates the use of a multi-parent constraint operating with three different sources (Pistol_Holster, Pistol Offset, RightHand_PistolGrip) at runtime.
The result is made possible by synchronizing two animation clips on multiple State Machine Layers: Pistol_Equip (read only .fbx playing on the Base Layer) and Rig_Pistol_Equip (native Unity animation clip playing in the Rig Pistol Layer).
The .fbx Ninja contains LeftFootIK and RightFootIK objects (both children of the LowerBody GO) that have been animated in a DCC to match the Skeleton feet animation.
Multi-parent constraints are used to attach the Feet IK effectors from the Leg IK Rig to the LeftFootIK and RightFootIK game objects. This creates the ability to lock both feet at the Root level allowing us to manipulate the hips without having the lower body parts go underground.
Finally, the Two Bone IK constraint provides the IK solve we need to generate the proper animation correction on the lower body (i.e. feet & hint placement ).
A very successful discovery was using the Multi-Referential constraint for a foot rig. We’ve been able to leverage the manipulation of the IK effector by creating a multi-pivot foot control rig… alluding to a future animation authoring solution.
We’ve duplicated the Left-Hand Game Objects hierarchy to create a different hand grip pose. Using the Rig component weight sliders, we can enable/disable the multiple Override Transform constraints (one for each of the finger Game Objects) in local mode to override the local rotation of each finger.
To align the LHIK Effector to the AR_LHIK_Target_B Game Object, we set the weight of the AR_LHIK_Target to 0 and at the same time the weight of the AR_LHIK_Target_B to 1.
We then use a MonoBehaviour script to synchronize the LeftHandGrip Rig weight properties and the LeftArm IK / Multi-Parent Constraint sources weight properties (AR_LHIK_Target & AR_LHIK_Target_B) to modify the Left-Hand grip pose and position on the weapon.
The Twist Correction Rig acts as a procedural deformation rig. It affects the upper and lower part of each arm, as well as both upper portions of each leg. It extracts the roll rotation of the wrist bone and distributes it along the local X-axis of each twist bone according to a specific weight value.
In this example, the Twist correction is at the bottom of the Rig Builder Rig Layers. The Twist Correction can then benefit from previous alterations induced by the preceding rigging constraints.
Since we are using the Animator state machine to drive the constraint properties (float weights), they will inherit the transition and blending effects that come with it (ex: value may not be absolute before the blend ends… you might expect to see a value like 0.998). Make sure to leave time for your blend transitions to end before the constraint weight animation starts to avoid this issue.
Another side effect of this approach is that you may need to key properties that were affected by a previous state to ensure that they do not go back to their default value/state. This is especially important when a state does not have a clip on the synced layer.
After addressing these issues, we ended up with something very functional and promising.
We are now delighted to share the result of this experimentation with you, with hopes of getting your feedback and input on how you are using or hope to use this Animation Rigging package.
You can download the Animation Rigging Advanced Character Interaction project on GitHub.
Have fun, and we’re looking forward to hearing from you on the animation rigging package forum!
Want to continue learning about rigging? Check out our courses and tutorials on the Unity Learn Premium platform.
Special thanks to Yang-Hai Eakes, Simon Bouvier-Zappa, Olivier Dionne, Dave Hunt, and Sven Santema.