CubismMotionLayer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using Live2D.Cubism.Framework.MotionFade;
  8. using System;
  9. using System.Collections.Generic;
  10. using UnityEngine;
  11. using UnityEngine.Animations;
  12. using UnityEngine.Playables;
  13. namespace Live2D.Cubism.Framework.Motion
  14. {
  15. /// <summary>
  16. /// Cubism motion layer.
  17. /// </summary>
  18. public class CubismMotionLayer : ICubismFadeState
  19. {
  20. #region Action
  21. /// <summary>
  22. /// Action animation end handler.
  23. /// </summary>
  24. public Action<int, float> AnimationEndHandler;
  25. #endregion
  26. #region Variable
  27. /// <summary>
  28. /// Playable output.
  29. /// </summary>
  30. public AnimationMixerPlayable PlayableOutput { get; private set; }
  31. /// <summary>
  32. /// Playable output.
  33. /// </summary>
  34. private PlayableGraph _playableGraph;
  35. /// <summary>
  36. /// Cubism playing motions.
  37. /// </summary>
  38. private List<CubismFadePlayingMotion> _playingMotions;
  39. /// <summary>
  40. /// Cubism playing motions.
  41. /// </summary>
  42. private CubismMotionState _motionState;
  43. /// <summary>
  44. /// List of cubism fade motion.
  45. /// </summary>
  46. private CubismFadeMotionList _cubismFadeMotionList;
  47. /// <summary>
  48. /// Layer index.
  49. /// </summary>
  50. private int _layerIndex;
  51. /// <summary>
  52. /// Layer weight.
  53. /// </summary>
  54. private float _layerWeight;
  55. /// <summary>
  56. /// Animation is finished.
  57. /// </summary>
  58. private bool _isFinished;
  59. /// <summary>
  60. /// Is finished.
  61. /// </summary>
  62. /// <returns>True if the animation is finished, false otherwise.</returns>
  63. public bool IsFinished
  64. {
  65. get { return _isFinished; }
  66. }
  67. #endregion
  68. #region Fade State Interface
  69. /// <summary>
  70. /// Get cubism playing motion list.
  71. /// </summary>
  72. /// <returns>Cubism playing motion list.</returns>
  73. public List<CubismFadePlayingMotion> GetPlayingMotions()
  74. {
  75. return _playingMotions;
  76. }
  77. /// <summary>
  78. /// Is default state.
  79. /// </summary>
  80. /// <returns><see langword="true"/> State is default; <see langword="false"/> otherwise.</returns>
  81. public bool IsDefaultState()
  82. {
  83. return false;
  84. }
  85. /// <summary>
  86. /// Get layer weight.
  87. /// </summary>
  88. /// <returns>Layer weight.</returns>
  89. public float GetLayerWeight()
  90. {
  91. return _layerWeight;
  92. }
  93. /// <summary>
  94. /// Get state transition finished.
  95. /// </summary>
  96. /// <returns><see langword="true"/> State transition is finished; <see langword="false"/> otherwise.</returns>
  97. public bool GetStateTransitionFinished()
  98. {
  99. return true;
  100. }
  101. /// <summary>
  102. /// Set state transition finished.
  103. /// </summary>
  104. /// <param name="isFinished">State is finished.</param>
  105. public void SetStateTransitionFinished(bool isFinished) {}
  106. /// <summary>
  107. /// Stop animation.
  108. /// </summary>
  109. /// <param name="index">Playing motion index.</param>
  110. public void StopAnimation(int index)
  111. {
  112. // Remove from playing motion list.
  113. _playingMotions.RemoveAt(index);
  114. }
  115. /// <summary>
  116. /// Stop animation.
  117. /// </summary>
  118. public void StopAnimationClip()
  119. {
  120. // Remove from motion state list.
  121. if (_motionState == null)
  122. {
  123. return;
  124. }
  125. _playableGraph.Disconnect(_motionState.ClipMixer, 0);
  126. _motionState = null;
  127. _isFinished = true;
  128. StopAllAnimation();
  129. }
  130. #endregion
  131. #region Function
  132. /// <summary>
  133. /// Initialize motion layer.
  134. /// </summary>
  135. /// <param name="playableGraph">.</param>
  136. /// <param name="fadeMotionList">.</param>
  137. /// <param name="layerWeight">.</param>
  138. public static CubismMotionLayer CreateCubismMotionLayer(PlayableGraph playableGraph, CubismFadeMotionList fadeMotionList, int layerIndex, float layerWeight = 1.0f)
  139. {
  140. var ret = new CubismMotionLayer();
  141. ret._playableGraph = playableGraph;
  142. ret._cubismFadeMotionList = fadeMotionList;
  143. ret._layerIndex = layerIndex;
  144. ret._layerWeight = layerWeight;
  145. ret._isFinished = true;
  146. ret._motionState = null;
  147. ret._playingMotions = new List<CubismFadePlayingMotion>();
  148. ret.PlayableOutput = AnimationMixerPlayable.Create(playableGraph, 1);
  149. return ret;
  150. }
  151. /// <summary>
  152. /// Create fade playing motion.
  153. /// </summary>
  154. /// <param name="clip">Animator clip.</param>
  155. /// <param name="speed">Animation speed.</param>
  156. private CubismFadePlayingMotion CreateFadePlayingMotion(AnimationClip clip, bool isLooping, float speed = 1.0f)
  157. {
  158. var ret = new CubismFadePlayingMotion();
  159. var isNotFound = true;
  160. var instanceId = -1;
  161. var events = clip.events;
  162. for(var i = 0; i < events.Length; ++i)
  163. {
  164. if(events[i].functionName != "InstanceId")
  165. {
  166. continue;
  167. }
  168. instanceId = events[i].intParameter;
  169. }
  170. for (int i = 0; i < _cubismFadeMotionList.MotionInstanceIds.Length; i++)
  171. {
  172. if(_cubismFadeMotionList.MotionInstanceIds[i] != instanceId)
  173. {
  174. continue;
  175. }
  176. isNotFound = false;
  177. ret.Speed = speed;
  178. ret.StartTime = Time.time;
  179. ret.FadeInStartTime = Time.time;
  180. ret.Motion = _cubismFadeMotionList.CubismFadeMotionObjects[i];
  181. ret.EndTime = (ret.Motion.MotionLength <= 0)
  182. ? -1
  183. : ret.StartTime + ret.Motion.MotionLength / speed;
  184. ret.IsLooping = isLooping;
  185. ret.Weight = 0.0f;
  186. break;
  187. }
  188. if(isNotFound)
  189. {
  190. Debug.LogError("CubismMotionController : Not found motion from CubismFadeMotionList.");
  191. }
  192. return ret;
  193. }
  194. /// <summary>
  195. /// Play animation.
  196. /// </summary>
  197. /// <param name="clip">Animation clip.</param>
  198. /// <param name="isLoop">Animation is loop.</param>
  199. /// <param name="speed">Animation speed.</param>
  200. public void PlayAnimation(AnimationClip clip, bool isLoop = true, float speed = 1.0f)
  201. {
  202. if (_motionState != null)
  203. {
  204. _playableGraph.Disconnect(_motionState.ClipMixer, 0);
  205. }
  206. // Create cubism motion state.
  207. _motionState = CubismMotionState.CreateCubismMotionState(_playableGraph, clip, isLoop, speed);
  208. #if UNITY_2018_2_OR_NEWER
  209. PlayableOutput.DisconnectInput(0);
  210. #else
  211. PlayableOutput.GetGraph().Disconnect(PlayableOutput, 0);
  212. #endif
  213. PlayableOutput.ConnectInput(0, _motionState.ClipMixer, 0);
  214. PlayableOutput.SetInputWeight(0, 1.0f);
  215. // Set last motion end time and fade in start time;
  216. if ((_playingMotions.Count > 0) && (_playingMotions[_playingMotions.Count - 1].Motion != null))
  217. {
  218. var motion = _playingMotions[_playingMotions.Count - 1];
  219. var time = Time.time;
  220. var newEndTime = time + motion.Motion.FadeOutTime;
  221. if (newEndTime < 0.0f || newEndTime < motion.EndTime)
  222. {
  223. motion.EndTime = newEndTime;
  224. }
  225. while (motion.IsLooping)
  226. {
  227. if ((motion.StartTime + motion.Motion.MotionLength) >= time)
  228. {
  229. break;
  230. }
  231. motion.StartTime += motion.Motion.MotionLength;
  232. }
  233. _playingMotions[_playingMotions.Count - 1] = motion;
  234. }
  235. // Create fade playing motion.
  236. var playingMotion = CreateFadePlayingMotion(clip, isLoop, speed);
  237. _playingMotions.Add(playingMotion);
  238. _isFinished = false;
  239. }
  240. /// <summary>
  241. /// Stop all animation.
  242. /// </summary>
  243. public void StopAllAnimation()
  244. {
  245. for(var i = _playingMotions.Count - 1; i >= 0; --i)
  246. {
  247. StopAnimation(i);
  248. }
  249. }
  250. /// <summary>
  251. /// Set layer weight.
  252. /// </summary>
  253. /// <param name="weight">Layer weight.</param>
  254. public void SetLayerWeight(float weight)
  255. {
  256. _layerWeight = weight;
  257. }
  258. /// <summary>
  259. /// Set state speed.
  260. /// </summary>
  261. /// <param name="index">index of playing motion list.</param>
  262. /// <param name="speed">Animation speed.</param>
  263. public void SetStateSpeed(int index, float speed)
  264. {
  265. // Fail silently...
  266. if(index < 0)
  267. {
  268. return;
  269. }
  270. var playingMotionData = _playingMotions[index];
  271. playingMotionData.Speed = speed;
  272. playingMotionData.EndTime = (playingMotionData.EndTime - Time.time) / speed;
  273. _playingMotions[index] = playingMotionData;
  274. _motionState.ClipMixer.SetSpeed(speed);
  275. _motionState.ClipPlayable.SetDuration(_motionState.Clip.length / speed - 0.0001f);
  276. }
  277. /// <summary>
  278. /// Set state is loop.
  279. /// </summary>
  280. /// <param name="index">index of playing motion list.</param>
  281. /// <param name="isLoop">Animation is loop.</param>
  282. public void SetStateIsLoop(int index, bool isLoop)
  283. {
  284. // Fail silently...
  285. if(index < 0)
  286. {
  287. return;
  288. }
  289. if(isLoop)
  290. {
  291. _motionState.ClipPlayable.SetDuration(double.MaxValue);
  292. }
  293. else
  294. {
  295. _motionState.ClipPlayable.SetDuration(_motionState.Clip.length - 0.0001f);
  296. }
  297. }
  298. #endregion
  299. public void Update()
  300. {
  301. // Fail silently...
  302. if (AnimationEndHandler == null || _playingMotions.Count != 1 || _isFinished
  303. || _motionState.ClipPlayable.GetDuration() == double.MaxValue || Time.time <= _playingMotions[0].EndTime)
  304. {
  305. return;
  306. }
  307. _isFinished = true;
  308. var instanceId = -1;
  309. var events = _motionState.Clip.events;
  310. for (var i = 0; i < events.Length; ++i)
  311. {
  312. if (events[i].functionName != "InstanceId")
  313. {
  314. continue;
  315. }
  316. instanceId = events[i].intParameter;
  317. }
  318. AnimationEndHandler(_layerIndex, instanceId);
  319. }
  320. }
  321. }