Motion

Updated: 11/28/2024

Summary

Motion allows you to play back animations from scripts without having to set up a state machine in Unity’s Mecanim.

Motion requires the CubismFadeController component and Unity’s Animator.
When an AnimatorController is set as the Animator component, the AnimatorController’s animation will be played instead of Motion.

The corresponding tutorial article can be found at Play back motion from scripts

Motion performs the following processes.

  1. Create PlayableGraph
  2. Create CubismMotionLayer
  3. Play back Animation
  4. Stop Animation

Create PlayableGraph

PlayableGraph is used to output animations, etc.
See the official Unity documentation for more information.

// Disable PlayableGraph on Animator side
var graph = animator.playableGraph;
if(graph.IsValid())
{
    graph.GetOutput(0).SetWeight(0);
}

// Create PlayableGraph
_playableGraph = PlayableGraph.Create("Playable Graph : " + this.FindCubismModel().name);
_playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);

// Create Playable for result output
_playableOutput = AnimationPlayableOutput.Create(_playableGraph, "Animation", animator);
_playableOutput.SetWeight(1);

// Create Playable to composite layers
_layerMixer = AnimationLayerMixerPlayable.Create(_playableGraph, LayerCount);

// Set default output destination
_playableOutput.SetSourcePlayable(_layerMixer);

This is done by CubismMotionController.OnEnable().

Create CubismMotionLayer

CubismMotionLayer allows multiple motions to be played back in parallel.

// Create cubism motion layers.
_motionLayers = new CubismMotionLayer[LayerCount];
for(var i = 0; i < LayerCount; ++i)
{
    _motionLayers[i] = CubismMotionLayer.CreateCubismMotionLayer(_playableGrap, _cubismFadeMotionList);
    _motionLayers[i].AnimationEndHandler += OnAnimationEnd;
    _layerMixer.ConnectInput(i, _motionLayers[i].PlayableOutput, 0);
    _layerMixer.SetInputWeight(i, 1.0f);
}

This is done by CubismMotionController.OnEnable().

When motion is played on multiple layers simultaneously, if they operate on the same CubismParameter.Value, it will be overwritten by the value set the latest.
The weight for overwriting can be set with CubismMotionLayer.SetLayerWeight (float weight).
If you set weights on the CubismMotionLayer, you must also set weights on the AnimationLayerMixerPlayable at the same time.

See the official Unity documentation for more information on AnimationLayerMixerPlayable.

_motionLayers[layerIndex].SetLayerWeight(weight);
_layerMixer.SetInputWeight(layerIndex, weight);

Play back Animation

Animation can be played by using CubismMotionController.PlayAnimation(AnimationClip clip, int layerIndex = 0, int priority = CubismMotionPriority.PriorityNormal, bool isLoop = true, float speed = 1.0f).

  • AnimationClip clip: Animation clip to be played.
  • int layerIndex: Index of animation playback layer.
  • int priority: Priority of the animation to be played. If the animation is to be played by plugging it into the currently playing animation, the value should be greater than the priority set for that animation.
  • bool isLoop: Determines whether the animation is looping or not. The default is looping.
  • float speed: Animation playback speed. The value must be greater than or equal to 0, and the default is 1 (normal playback speed).

Stop Animation

Use CubismMotionController.StopAnimation (int animationIndex, int layerIndex = 0) to stop the animation of the specified index.

  • int animationIndex: Index of the animation to be stopped.
  • int layerIndex: Layer index of the animation to be stopped.

Use CubismMotionController.StopAllAnimation () to stop all animations.

Callbacks when animation is played and stopped

Cubism SDK for Unity allows callbacks to retrieve events when animation is played and stopped.

Callback when animation plays

The sample code to receive a callback when animation is played is shown below. It is assumed that the model has been imported in advance.

private CubismMotionController _motionController;
private CubismFadeMotionList _cubismFadeMotionList;

// Start is called before the first frame update
private void Start()
{
    _motionController = GetComponent<CubismMotionController>();

    _cubismFadeMotionList = GetComponent<CubismFadeController>().CubismFadeMotionList;
    _motionController.AnimationBeginHandler += OnAnimationBegin;
}

private void OnAnimationBegin(int instanceId)
{
    if (! _cubismFadeMotionList)
    {
        return;
    }

    for (int i = 0; i < _cubismFadeMotionList.MotionInstanceIds.Length; i++)
    {
        if (_cubismFadeMotionList.MotionInstanceIds[i] ! = instanceId)
        {
            continue;
        }

        Debug.Log("StartedMotion: " + _cubismFadeMotionList.CubismFadeMotionObjects[i].MotionName);
        break;
    }
}

In this code, register a user-created OnAnimationBegin() function to CubismMotionController.AnimationBeginHandler.

Tips

Under the following condition, the playback callback will not work.

  • When null is registered in the callback

Callback when animation is stopped

The sample code to receive a callback when animation is stopped is shown below.

private CubismMotionController _motionController;
private CubismFadeMotionList _cubismFadeMotionList;

// Start is called before the first frame update
void Start()
{
    _motionController = GetComponent<CubismMotionController>();

    _cubismFadeMotionList = GetComponent<CubismFadeController>().CubismFadeMotionList;
    _motionController.AnimationEndHandler += OnAnimationEnd;
}

void OnAnimationEnd(int instanceId)
{
    if (! _cubismFadeMotionList)
    {
        return;
    }

    for (int i = 0; i < _cubismFadeMotionList.MotionInstanceIds.Length; i++)
    {
        if (_cubismFadeMotionList.MotionInstanceIds[i] ! = instanceId)
        {
            continue;
        }

        Debug.Log("EndedMotion: " + _cubismFadeMotionList.CubismFadeMotionObjects[i].MotionName);
        break;
    }
}

In this code, register a user-created OnAnimationEnd() function to CubismMotionController.AnimationEndHandler.
This callback is called when the animation finishes playing or is stopped.

Tips

Note that the stop callback cannot be called under the following conditions.

  • When the motion being played is set as “looping”
  • When null is registered in the callback

Was this article helpful?
YesNo
Please let us know what you think about this article.