Ad-Hoc/Sequential Animation System Using Unity Playable API

State machines are widely used in video game engines to control complex animations of objects such as characters etc. The two major commercial engines, Unity and Unreal implement their own version of state machines to facilitate constructing complex animations. Unity’s Mecanim , a visual FSM tool, for example, provides an easy way to define animation states and their transitions.

Advantages:

Mecanim provides few advantages:
-A graphical interface that allows interaction with the animation system and, by design, provides a visual map of the whole system.
-Exerting control over transitions from one state to another.
-Allows animators and designers to modify animation system without the need for an engineer.
-Reduce complexity of interactions between animation.

However, there are few disadvantages to using a state machine, specifically Mecanim. Before mentioning them, I would like to stress the fact that like the advantages mentioned above these depend on the use case.

When you have a lot of animations, things get messy… like really messy.

Good luck debugging this

This is a classic state machine problem. Transitions increase exponentially with the increase of states. Understanding the whole system becomes hard, debugging transitions becomes even harder.

Nonetheless, there are few techniques that help manage complexity. Firewatch by Compo Santo was made in Unity. They have used Mecanim to create their locomotion system..and may I say, successfully. They had to deal with tons of animation states and they used several techniques explained in this excellent talk by William Armstrong.

But what if you don’t know the total number of animations that will be used? and what if additional animations are added after release? What if the characters don’t share similar animation states?

All these questions point to the limitation of state machine. At least in Mecanim’s case, it’s not possible to add or remove states at run-time. In a way, all states are predefined. Yes, it’s possible to override the whole Animation Controller but you are still stuck with the same states and transitions.

Ad-Hoc/Sequential Animation System

Here are the requirements for a project I was working on:
1- Characters are in 3D.
2- Characters don’t have complex states or transitions.
3- An animation transition don’t happens frequently. The shortest animation clip is 0.5s .
4- The total number of animations is not defined.
5- A character could have many animation clips.

It was clear to me that implementing an animation system using Mecanim would be challenging and might not satisfy the projects requirements.

Fortunately, Unity introduced Playable API as a new way (late 2017?) to control animation systems. Playable API is the low-level API that Mecanim and all animation related systems in Unity use to play animation clips.

The flexibility provided by Playables made it a great fit for the system I was trying to implement.

The system

The idea here is that animation clips are extracted from their FBX file and saved individually. When a state change is triggered, an animation file is loaded and added to the playable graph. The playable graph is composed of 2 playable “slots”, an animator controller and 2 mixers.

    //Sample code. Not production ready.
    [Serializable]
    public class pContainer
    {
        public string name;
        public int inputIndex, outputIndex; // inputIndex to the mixer not the actual slot input
        public float weight;
    }

    [Serializable]
    public class Slot : pContainer
    {
        public AnimationClipPlayable pClip;
    }

    [Serializable]
    public class Mixer : pContainer
    {
        public AnimationMixerPlayable pMixer;
    }

    [Serializable]
    public class Controller : pContainer
    {
        public AnimatorControllerPlayable pController;
    }

Let’s talk about the animator (Mecanim state machine) first. Our characters have a common state machine that consist of 2 states, talking and idle. These states could easily be implemented as playables without a state machine. However, I chose to keep the state machine to provide a common structure for character animation that could be expanded in the future if necessary.

The 2 playable slots are used to blend two Ad-Hoc animation clips. When an animation clip is added, it’s assigned to a “free” slot. The slot state is set to “active” and when a new animation clip is added, it’s assigned to the other slot, which is “free”. An animation blend is then initiated using the slots mixer.

The slots mixer is an input to the main mixer, the other input to the main mixer is the animator controller. When both slots are free, a blend from slots mixer to animator controller is initiated.

    //Sample code. Not production ready.
    public void Initialize()
    {
        mainMixer = new Mixer();
        slotsMixer = new Mixer();
        pAnimator = new Controller();
        slot1 = new Slot();
        slot2 = new Slot();

        slotsMixer.inputIndex = 0;
        pAnimator.inputIndex = 1;
        slot1.inputIndex = 0;
        slot2.inputIndex = 1;

        graph = PlayableGraph.Create();

        mainMixer.pMixer = AnimationMixerPlayable.Create(graph, 2);
        slotsMixer.pMixer = AnimationMixerPlayable.Create(graph, 2);
        slotsMixer.weight = 0f;

        pAnimator.pController = AnimatorControllerPlayable.Create(graph, controller);
        pAnimator.weight = 1f;


        slotsMixer.pMixer.ConnectInput(slot1.inputIndex, slot1.pClip, 0); // inputIndex to the mixer not the actual slot input
        slotsMixer.pMixer.ConnectInput(slot2.inputIndex, slot2.pClip, 0);

        mainMixer.pMixer.ConnectInput(slotsMixer.inputIndex, slotsMixer.pMixer, 0);
        mainMixer.pMixer.ConnectInput(pAnimator.inputIndex, pAnimator.pController, 0);

        var playableOutput = AnimationPlayableOutput.Create(graph, "Animation", GetComponent<Animator>());
        playableOutput.SetSourcePlayable(mainMixer.pMixer);


        graph.Play();

        activeSlot = SlotState.slot2;
    }

The blend duration could be adjusted and animation clips are wrapped in a scriptable object to add base weight and meta data.

There is a cost to adding animation clips at run time. Every time a clip is added, the graph needs to be reconstructed (Playables are implemented as structs to avoid GC), according to Unity it’s faster than instantiating a game object. More work is needed to investigate this cost. However, for the purpose of this project, this cost is negligible since reconstructing the graph will occur once every 0.5s at most.

Generally speaking, this system may not be suitable for projects where state transitions and their properties have to be tweaked in depth and require detailed control. However, it could provide a good compromise by mixing a base character animation state machine with ad-hoc animation clips. Also, projects that require many transitions per second (Fighting game?) would not be a great fit due to graph reconstruction cost mentioned above.

Further work

I’ve experimented with creating layers using playable API but didn’t implement it in production. I would like to create a system that controls several regions in the character separately, for example, the ability to play an animation clip on the lower body and another one on the right hand.

Leave a Reply

Your email address will not be published. Required fields are marked *