CubismFadeController.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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.Core;
  8. using Live2D.Cubism.Framework.Motion;
  9. using UnityEngine;
  10. namespace Live2D.Cubism.Framework.MotionFade
  11. {
  12. /// <summary>
  13. /// Cubism fade controller.
  14. /// </summary>
  15. [RequireComponent(typeof(Animator))]
  16. public class CubismFadeController : MonoBehaviour, ICubismUpdatable
  17. {
  18. #region Variable
  19. /// <summary>
  20. /// Cubism fade motion list.
  21. /// </summary>
  22. [SerializeField]
  23. public CubismFadeMotionList CubismFadeMotionList;
  24. /// <summary>
  25. /// Parameters cache.
  26. /// </summary>
  27. private CubismParameter[] DestinationParameters { get; set; }
  28. /// <summary>
  29. /// Parts cache.
  30. /// </summary>
  31. private CubismPart[] DestinationParts { get; set; }
  32. /// <summary>
  33. /// Model has motion controller component.
  34. /// </summary>
  35. private CubismMotionController _motionController;
  36. /// <summary>
  37. /// Model has cubism update controller component.
  38. /// </summary>
  39. [HideInInspector]
  40. public bool HasUpdateController { get; set; }
  41. /// <summary>
  42. /// Fade state machine behavior set in the animator.
  43. /// </summary>
  44. private ICubismFadeState[] _fadeStates;
  45. /// <summary>
  46. /// Model has animator component.
  47. /// </summary>
  48. private Animator _animator;
  49. /// <summary>
  50. /// Restore parameter value.
  51. /// </summary>
  52. private CubismParameterStore _parameterStore;
  53. /// <summary>
  54. /// Fading flags for each layer.
  55. /// </summary>
  56. private bool[] _isFading;
  57. #endregion
  58. #region Function
  59. /// <summary>
  60. /// Refreshes the controller. Call this method after adding and/or removing <see cref="CubismFadeParameter"/>s.
  61. /// </summary>
  62. public void Refresh()
  63. {
  64. _animator = GetComponent<Animator>();
  65. // Fail silently...
  66. if (_animator == null)
  67. {
  68. return;
  69. }
  70. DestinationParameters = this.FindCubismModel().Parameters;
  71. DestinationParts = this.FindCubismModel().Parts;
  72. _motionController = GetComponent<CubismMotionController>();
  73. _parameterStore = GetComponent<CubismParameterStore>();
  74. // Get cubism update controller.
  75. HasUpdateController = (GetComponent<CubismUpdateController>() != null);
  76. _fadeStates = (ICubismFadeState[])_animator.GetBehaviours<CubismFadeStateObserver>();
  77. if ((_fadeStates == null || _fadeStates.Length == 0) && _motionController != null)
  78. {
  79. _fadeStates = _motionController.GetFadeStates();
  80. }
  81. if (_fadeStates == null)
  82. {
  83. return;
  84. }
  85. _isFading = new bool[_fadeStates.Length];
  86. }
  87. /// <summary>
  88. /// Called by cubism update controller. Order to invoke OnLateUpdate.
  89. /// </summary>
  90. public int ExecutionOrder
  91. {
  92. get { return CubismUpdateExecutionOrder.CubismFadeController; }
  93. }
  94. /// <summary>
  95. /// Called by cubism update controller. Needs to invoke OnLateUpdate on Editing.
  96. /// </summary>
  97. public bool NeedsUpdateOnEditing
  98. {
  99. get { return false; }
  100. }
  101. /// <summary>
  102. /// Called by cubism update controller. Updates controller.
  103. /// </summary>
  104. /// <remarks>
  105. /// Make sure this method is called after any animations are evaluated.
  106. /// </remarks>
  107. public void OnLateUpdate()
  108. {
  109. // Fail silently.
  110. if (!enabled || _fadeStates == null || _parameterStore == null
  111. || DestinationParameters == null || DestinationParts == null)
  112. {
  113. return;
  114. }
  115. var time = Time.time;
  116. for (var i = 0; i < _fadeStates.Length; ++i)
  117. {
  118. _isFading[i] = false;
  119. var playingMotions = _fadeStates[i].GetPlayingMotions();
  120. if (playingMotions == null || playingMotions.Count <= 1)
  121. {
  122. continue;
  123. }
  124. var latestPlayingMotion = playingMotions[playingMotions.Count - 1];
  125. var playingMotionData = latestPlayingMotion.Motion;
  126. var elapsedTime = time - latestPlayingMotion.FadeInStartTime;
  127. for (var j = 0; j < playingMotionData.ParameterFadeInTimes.Length; j++)
  128. {
  129. if ((elapsedTime <= playingMotionData.FadeInTime) ||
  130. ((0 <= playingMotionData.ParameterFadeInTimes[j]) &&
  131. (elapsedTime <= playingMotionData.ParameterFadeInTimes[j])) ||
  132. !_fadeStates[i].GetStateTransitionFinished())
  133. {
  134. _isFading[i] = true;
  135. break;
  136. }
  137. }
  138. }
  139. var isFadingAllFinished = true;
  140. for (var i = 0; i < _fadeStates.Length; ++i)
  141. {
  142. if (_isFading[i])
  143. {
  144. isFadingAllFinished = false;
  145. continue;
  146. }
  147. var playingMotions = _fadeStates[i].GetPlayingMotions();
  148. for (var j = playingMotions.Count - 2; j >= 0; --j)
  149. {
  150. var playingMotion = playingMotions[j];
  151. if (time <= playingMotion.EndTime)
  152. {
  153. continue;
  154. }
  155. // If fade-in has been completed, delete the motion that has been played back.
  156. _fadeStates[i].StopAnimation(j);
  157. }
  158. }
  159. if (isFadingAllFinished)
  160. {
  161. return;
  162. }
  163. _parameterStore.RestoreParameters();
  164. // Update sources and destinations.
  165. for (var i = 0; i < _fadeStates.Length; ++i)
  166. {
  167. if (!_isFading[i])
  168. {
  169. continue;
  170. }
  171. UpdateFade(_fadeStates[i]);
  172. }
  173. }
  174. /// <summary>
  175. /// Update motion fade.
  176. /// </summary>
  177. /// <param name="fadeState">Fade state observer.</param>
  178. private void UpdateFade(ICubismFadeState fadeState)
  179. {
  180. var playingMotions = fadeState.GetPlayingMotions();
  181. if (playingMotions == null)
  182. {
  183. // Do not process if there is only one motion, if it does not switch.
  184. return;
  185. }
  186. // Weight set for the layer being processed.
  187. // (In the case of the layer located at the top, it is forced to 1.)
  188. var layerWeight = fadeState.GetLayerWeight();
  189. var time = Time.time;
  190. // Calculate MotionFade.
  191. for (var i = 0; i < playingMotions.Count; i++)
  192. {
  193. var playingMotion = playingMotions[i];
  194. var fadeMotion = playingMotion.Motion;
  195. if (fadeMotion == null)
  196. {
  197. continue;
  198. }
  199. var elapsedTime = time - playingMotion.FadeInStartTime;
  200. var endTime = playingMotion.EndTime - elapsedTime;
  201. var fadeInTime = fadeMotion.FadeInTime;
  202. var fadeOutTime = fadeMotion.FadeOutTime;
  203. var fadeInWeight = (fadeInTime <= 0.0f)
  204. ? 1.0f
  205. : CubismFadeMath.GetEasingSine(elapsedTime / fadeInTime);
  206. var fadeOutWeight = (fadeOutTime <= 0.0f || playingMotion.EndTime < 0.0f)
  207. ? 1.0f
  208. : CubismFadeMath.GetEasingSine((playingMotion.EndTime - time) / fadeOutTime);
  209. playingMotions[i] = playingMotion;
  210. var motionWeight = fadeInWeight * fadeOutWeight * layerWeight;
  211. // Apply to parameter values
  212. for (var j = 0; j < DestinationParameters.Length; ++j)
  213. {
  214. var index = -1;
  215. for (var k = 0; k < fadeMotion.ParameterIds.Length; ++k)
  216. {
  217. if (fadeMotion.ParameterIds[k] != DestinationParameters[j].Id)
  218. {
  219. continue;
  220. }
  221. index = k;
  222. break;
  223. }
  224. if (index < 0)
  225. {
  226. // There is not target ID curve in motion.
  227. continue;
  228. }
  229. var value = fadeMotion.ParameterCurves[index].Evaluate(elapsedTime);
  230. if (DestinationParameters[j].IsRepeat())
  231. {
  232. value = DestinationParameters[j].GetParameterRepeatValue(value);
  233. }
  234. else
  235. {
  236. value = DestinationParameters[j].GetParameterClampValue(value);
  237. }
  238. value = Evaluate(
  239. value, elapsedTime, endTime,
  240. fadeInWeight, fadeOutWeight,
  241. fadeMotion.ParameterFadeInTimes[index], fadeMotion.ParameterFadeOutTimes[index],
  242. motionWeight, DestinationParameters[j].Value);
  243. DestinationParameters[j].OverrideValue(value);
  244. }
  245. // Apply to part opacities
  246. for (var j = 0; j < DestinationParts.Length; ++j)
  247. {
  248. var index = -1;
  249. for (var k = 0; k < fadeMotion.ParameterIds.Length; ++k)
  250. {
  251. if (fadeMotion.ParameterIds[k] != DestinationParts[j].Id)
  252. {
  253. continue;
  254. }
  255. index = k;
  256. break;
  257. }
  258. if (index < 0)
  259. {
  260. // There is not target ID curve in motion.
  261. continue;
  262. }
  263. DestinationParts[j].Opacity = Evaluate(
  264. fadeMotion.ParameterCurves[index], elapsedTime, endTime,
  265. fadeInWeight, fadeOutWeight,
  266. fadeMotion.ParameterFadeInTimes[index], fadeMotion.ParameterFadeOutTimes[index],
  267. motionWeight, DestinationParts[j].Opacity);
  268. }
  269. }
  270. }
  271. /// <summary>
  272. /// Evaluate fade curve.
  273. /// </summary>
  274. /// <param name="curve">Curves to be evaluated.</param>
  275. /// <param name="elapsedTime">Elapsed Time.</param>
  276. /// <param name="endTime">Fading end time.</param>
  277. /// <param name="fadeInTime">Fade in time.</param>
  278. /// <param name="fadeOutTime">Fade out time.</param>
  279. /// <param name="parameterFadeInTime">Fade in time parameter.</param>
  280. /// <param name="parameterFadeOutTime">Fade out time parameter.</param>
  281. /// <param name="motionWeight">Motion weight.</param>
  282. /// <param name="currentValue">Current value with weight applied.</param>
  283. public float Evaluate(
  284. AnimationCurve curve, float elapsedTime, float endTime,
  285. float fadeInTime, float fadeOutTime,
  286. float parameterFadeInTime, float parameterFadeOutTime,
  287. float motionWeight, float currentValue)
  288. {
  289. if (curve.length <= 0)
  290. {
  291. return currentValue;
  292. }
  293. // Motion fade.
  294. return Evaluate(
  295. curve.Evaluate(elapsedTime), elapsedTime, endTime,
  296. fadeInTime, fadeOutTime,
  297. parameterFadeInTime, parameterFadeOutTime,
  298. motionWeight, currentValue);
  299. }
  300. /// <summary>
  301. /// Evaluate fade value.
  302. /// </summary>
  303. /// <param name="value">New value.</param>
  304. /// <param name="elapsedTime">Elapsed Time.</param>
  305. /// <param name="endTime">Fading end time.</param>
  306. /// <param name="fadeInTime">Fade in time.</param>
  307. /// <param name="fadeOutTime">Fade out time.</param>
  308. /// <param name="parameterFadeInTime">Fade in time parameter.</param>
  309. /// <param name="parameterFadeOutTime">Fade out time parameter.</param>
  310. /// <param name="motionWeight">Motion weight.</param>
  311. /// <param name="currentValue">Current value with weight applied.</param>
  312. public float Evaluate(
  313. float value, float elapsedTime, float endTime,
  314. float fadeInTime, float fadeOutTime,
  315. float parameterFadeInTime, float parameterFadeOutTime,
  316. float motionWeight, float currentValue)
  317. {
  318. // Motion fade.
  319. if (parameterFadeInTime < 0.0f &&
  320. parameterFadeOutTime < 0.0f)
  321. {
  322. return currentValue + (value - currentValue) * motionWeight;
  323. }
  324. // Parameter fade.
  325. float fadeInWeight, fadeOutWeight;
  326. if (parameterFadeInTime < 0.0f)
  327. {
  328. fadeInWeight = fadeInTime;
  329. }
  330. else
  331. {
  332. fadeInWeight = (parameterFadeInTime < float.Epsilon)
  333. ? 1.0f
  334. : CubismFadeMath.GetEasingSine(elapsedTime / parameterFadeInTime);
  335. }
  336. if (parameterFadeOutTime < 0.0f)
  337. {
  338. fadeOutWeight = fadeOutTime;
  339. }
  340. else
  341. {
  342. fadeOutWeight = (parameterFadeOutTime < float.Epsilon || (endTime < 0.0f))
  343. ? 1.0f
  344. : CubismFadeMath.GetEasingSine(endTime / parameterFadeOutTime);
  345. }
  346. var parameterWeight = fadeInWeight * fadeOutWeight;
  347. return currentValue + (value - currentValue) * parameterWeight;
  348. }
  349. #endregion
  350. #region Unity Events Handling
  351. /// <summary>
  352. /// Initializes instance.
  353. /// </summary>
  354. private void OnEnable()
  355. {
  356. // Initialize cache.
  357. Refresh();
  358. }
  359. /// <summary>
  360. /// Called by Unity.
  361. /// </summary>
  362. private void LateUpdate()
  363. {
  364. if (!HasUpdateController)
  365. {
  366. OnLateUpdate();
  367. }
  368. }
  369. #endregion
  370. }
  371. }