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.
- Create PlayableGraph
- Create CubismMotionLayer
- Play back Animation
- 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