Integrating compatible animations into Unity

NB: Before starting to create new animations that are compatible with KuteEngine, make sure you understand the fundamental animation types and their properties.

6 Steps

  1. Integrate animations into the Animator Controller

    1. RS (root state)

    2. OT (other-transition)

    3. ST (self-transition)

    4. STC (continuous/looped self-transition

    5. BA (body attitude)

    6. FS (facial stated)

    7. FOT (facial other-transition)

    8. FST (facial self-transition)

    9. Tail additive animations

    10. Neck-head-face additive animations

    11. Ear additive animations

    12. Feet additive animations

    13. Everything else (mostly one-off functional animations such as Blink or Breathing)

Step 1: Creating animation content in Blender

Animation content is initially created in Blender based on certain rules and conventions.

See Introduction to Blender Animation section.

Step 2: Blender to Unity export

Content is then exported via a simple button. This will convert one or more actions into separate FBX files and copy them into a Unity subfolder.

See Introduction to Blender Animation section.

Step 3: Animation configuration inside Unity

Each animation file needs to be configured to work with KuteEngine. There are required settings shared by all animation types (RS, ST, OT, ...), and some specific to each type.

3.1 - General settings

3.1.1 Model tab

From:

To:

3.1.2 Rig Tab

From:

To:

3.1.3 Animation tab

From:

To:

3.2 - Common settings for all animations

3.3 - RS

  • Loop Time checked

  • For certain animated, asymmetrical RS (like Walk or Run), some animations may require a cycle offset of 0.5.

3.4 - ST, OT and STC

  • In most cases, no other import settings need to be changed

  • For STC, it is necessary to have Loop Time checked

3.5 - BA

  • Start time set to frame 6 instead of 1

  • Looped

  • Use additive reference pose from first frame (1)

  • Optionally (to make the build smaller) use import mask Mask_BodyAdditive.

From:

To:

3.6 - Face_Additive

  • Not looped

  • Additive

  • Use Mask_NeckHeadFaceAdditive

3.7 - Face animations

  • Looped

  • Not additive

  • Use Mask_Face

  • Additive

  • Use corresponding mask

Step 4: Integrate animation into the Animator Controller

  • Always try to keep the number of STs as small as possible. For example, if you have L and R versions of the same animation, try to put them into a blend tree and check if they can be interpolated.

Always try to keep the number of STs as small as possible. For example, if you have L and R versions of the same animation, try to put them into a BlendTree and check if they are interpolatable. If not, create separate ST state.

4.1 - ST

  • Duplicate an existing ST

  • Rename it to make it easily understandable (no need to exactly name it the same as the animation, just a general name)

  • Make sure that the new one has tag “TransitionBehavior”

  • Also make sure it uses speed multiplier “TransitionSpeedMultiplier”

  • Make a transition to the root state

    • Exit Time = 1

    • Fixed Duration = false

    • Transition Duration = 0

    • (For some cases these parameters may be different - depends on the animation.)

  • If we want a 2D blend tree, set it to 2D Freeform Cartesian (always !).

    • First parameter (X-coordinate): often, but not always, TransitionLeftRight

    • Second parameter (Y-coordinate): TransitionIntensity

  • Set up the blend tree (or just a single motion) by using the necessary animator parameters:

    • TransitionIntensity

    • TransitionLeftRight

    • TransitionParameterA

    • TransitionParameterB

    • For locomotion RS, STs and RS: Move*

  • The best use of ‘TransitionIntensity’ depends on the use case. At ‘0’, the ST doesn't have to be ‘neutral’ (like Stand’). Zero just corresponds to the lowest intensity that makes sense for this ST.

    • In order to be able to use TransitionIntensity: create a blend tree with RS as the first motion, and the STC as the second.

    • Slow down the speed of the RS (so that the blending of both is not too fast - for example : 0.5).

    • If we want a minimum threshold of a blend (30% to 100%), set the RS minimum threshold to -0.3 instead of 0

4.2 - STC

  • Mostly like ST

  • Transition from ST to the STC

  • No transition to Root State

4.3 - RS

  • Can be either single states (like Stand) or complex blend trees (like Walk).

  • In any case, they MUST use their own animator parameters, never those starting with Transition* or those used in other parts of the animator controller. Examples:

    • MoveBackwardForward, MoveDownUp, MoveParameterA, etc (all starting with Move*)

4.4 - OT

  • Mostly like ST

  • Like ST, they can use both Transtion* parameters and RS parameters (such as Move*)

  • They are often less complex than their starting or ending RS. This means they have to start & end with a crossfade —> this is handled by code, see below.

4.5 - BA

  • Only in “FullBodyAttitudes” layer.

  • Create one parameter in the controller per BA animation, named “BA_***”

  • Add it to the Direct Blend Tree inside the corresponding animator state, by either adding a simple motion to it with the newly created parameter, or by adding a blend tree if the motion is complex.

Step 5: Integrate animations into KuteEngine (C#)

Once the animation states are created and configured inside the Controller (Step 4), you can then expose these states into C# data file. The animation states are then made accessible via a set of C#-based ‘data’ files. They are thereby exposed to the client-side AI.

NB: Right now it is not possible to extend ST, STC, OT, BA RS and Shared Settings code for a Being. This will be added in next release.

5.1 - RS

Root State
  • Create or open your own RootState script file that need to implement RS[BeingType].cs

  • Insert a new Root State as a property:

public static RSBeingType RS_NAME = new(nameof(RS_NAME ), 0);
  • Create or open your own SharedSettingsEditor script file that need to implement [BeingType]SharedSettingsEditor.cs

  • Inside the method OnInspectorGUI_InitActuatorData():

 RSInfos[RS_Name] = new RSInfo(
                Animator.StringToHash("RS_State_Name"),
                /* BA ... */,
                /* BA ... */,
                /* ST ... */
            );

5.2 - OT

Other Transition

You can either create a default transition between a RS to another (you dont have a specific animation for this transition), or create a named transition to specify a State inside the animator to use as this transition.

  • Create or open your own SharedSettingsEditor script file that need to implement [BeingType]SharedSettingsEditor.cs

  • Inside the method OnInspectorGUI_InitActuatorData()insert one of the following line:

InsertDefaultOT(RS_FROM, RS_TO);
InsertNamedOT(RS_FROM, RS_TO, "STATE_NAME");

For named OT, you can specify a CrossfadeTime (parameters): If greater than 0, do a crossfade (using normalized time) instead of an instant transition

5.3 - ST

Self Transition
  • Create or open your own ST script file that need to implement the ST[BeingType].cs of your being. (STFloater.cs, STHumanoid.cs, ...)

  • Add a new static field corresponding to your ST

public static STFloater NAME = new(false, nameof(NAME));
  • Create or open your own SharedSettingsEditor script file that need to implement [BeingType]SharedSettingsEditor.cs

  • Inside the method OnInspectorGUI_InitActuatorData(), on the line RSInfos[RS_NAME] = new RSInfo( …) , for the 4th parameter, add the ST like following:

RSInfos[...] = new RSInfo(
                ... , ... ,
                new RSInfo.ST_and_int[]
                {
                    ... ,
                    new(STFloater.RubFace.ID, AddS("ST_Stand_RubFace")),
                }
            );

5.4 - STC

Self Transition Cycled
  • Create or open your own ST script file that need to implement the ST[BeingType].cs of your being. (STFloater.cs, STHumanoid.cs, ...)

  • Add a new static field corresponding to your ST

public static STFloater NAME = new(true, nameof(NAME));
  • Create or open your own SharedSettingsEditor script file that need to implement [BeingType]SharedSettingsEditor.cs

  • Inside the method OnInspectorGUI_InitActuatorData(), on the line RSInfos[RS_NAME] = new RSInfo( …) , for the 4th parameter, add the ST like following:

new RSInfo.ST_and_int([STBird.NAME.ID], AddS(new STTransitionInfo(Animator.StringToHash("STC_Stand_NAME"), .5f))),

5.5 - BA

Body Attitude
  • Create or open your own BodyAttitude script file that need to implement BodyAttitude[BeingType].cs

  • Insert a new BodyAttitude:

public static BodyAttitudeBEING_TYPE BodyAttitudeName= new(
            nameof(BodyAttitudeName),
            1,
            Animator.StringToHash("Name_of_BA_State")
        );
  • Create or open your own SharedSettingsEditor script file that need to implement [BeingType]SharedSettingsEditor.cs

  • Inside the method OnInspectorGUI_InitActuatorData(), on the line RSInfos[RS_NAME] = new RSInfo( …) , for the 3rd parameter, add the BA like following:

new int[] { ..., BodyAttitudeBEING_TYPE.BodyAttitudeName.ID , ... }

5.6 - Last Step

When you have added everything you want in the SharedSettingsEditor, you need to select the [BeingType]SharedSettings scriptable object, scroll to the bottom, and click on "Update [BEING] animation data".

You can see the console logs and check if there is no error(s).

Step 6: Use the animation inside activity (AI-content)

Finally, activities are added or changed to use the new animations, which often includes adapting them procedurally.

Inside the MainProcess() method of activities, you can use multiple Service Activity component to switch the Root State of the being, or play ST, control the current RS etc...

There are multiple way to play animation, depending on the state the Being is in. Here is a following example of how to use the different animations types :

// Service activity that control the being when he is standing.
private Stay stay;

// Service activity that control how the being move.
private Locomotion locomotion;

protected override IEnumerator MainProcess()
{
    // 1 - RS
    // To change from a RS to another, you need to use service activity.
    stay.Start(); // By default, being is standing
    Vector3 goal = Vector3.zero;
    locomotion.Start(RS.Walk, goal); // The being change RS (stand -> walk) and move toward the goal 
    
    // 2 - OT
    // OT are played automatically depending on the state of the being, when he
    // transition from an RS to another.
    // However, certain Service Activities let you set a ITransitionType to specify a OT
    locomotion.SetTargetRS(RS.Walk, TransitionType.DefaultRight, ...);
    
    // 3 - ST
    // The way you play ST depends on the RS you are in.
    
    // 3.1 - Stand ST
    stay.RequestST(STBeing.Jump, /* the following parameter control the BlendTree if used */);
    
    // 4 - STC
    // Same way as ST
    
    // 5 - BA
     _stay.RequestBA(BodyAttitudeBeing.BA_Name, 1f);
    ...
}

Last updated