CubismExpressionController.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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.MotionFade;
  9. using System.Collections.Generic;
  10. using UnityEngine;
  11. namespace Live2D.Cubism.Framework.Expression
  12. {
  13. /// <summary>
  14. /// Expression controller.
  15. /// </summary>
  16. public class CubismExpressionController : MonoBehaviour, ICubismUpdatable
  17. {
  18. #region variable
  19. /// <summary>
  20. /// Expressions data list.
  21. /// </summary>
  22. [SerializeField]
  23. public CubismExpressionList ExpressionsList;
  24. /// <summary>
  25. /// Use the expression calculation method.
  26. /// </summary>
  27. [SerializeField]
  28. public bool UseLegacyBlendCalculation = false;
  29. /// <summary>
  30. /// CubismModel cache.
  31. /// </summary>
  32. private CubismModel _model = null;
  33. /// <summary>
  34. /// Playing expressions.
  35. /// </summary>
  36. private List<CubismPlayingExpression> _playingExpressions = new List<CubismPlayingExpression>();
  37. /// <summary>
  38. /// Playing expressions index.
  39. /// </summary>
  40. [SerializeField]
  41. public int CurrentExpressionIndex = -1;
  42. /// <summary>
  43. /// Last playing expressions index.
  44. /// </summary>
  45. private int _lastExpressionIndex = -1;
  46. /// <summary>
  47. /// Model has update controller component.
  48. /// </summary>
  49. [HideInInspector]
  50. public bool HasUpdateController { get; set; }
  51. /// <summary>
  52. /// Value of each parameter to be applied to the model.
  53. /// </summary>
  54. private List<CubismExpressionParameterValue> _expressionParameterValues = new List<CubismExpressionParameterValue>();
  55. /// <summary>
  56. /// Default value for applying additive.
  57. /// </summary>
  58. private const float DefaultAdditiveValue = 0.0f;
  59. /// <summary>
  60. /// Initial value of multiply applied.
  61. /// </summary>
  62. private const float DefaultMultiplyValue = 1.0f;
  63. #endregion
  64. /// <summary>
  65. /// Add new expression to playing expressions.
  66. /// </summary>
  67. private void StartExpression()
  68. {
  69. // Fail silently...
  70. if(ExpressionsList == null || ExpressionsList.CubismExpressionObjects == null)
  71. {
  72. return;
  73. }
  74. // Backup expression.
  75. _lastExpressionIndex = CurrentExpressionIndex;
  76. // Set last expression end time
  77. if(_playingExpressions.Count > 0)
  78. {
  79. var playingExpression = _playingExpressions[_playingExpressions.Count - 1];
  80. var newExpressionEndTime = playingExpression.ExpressionUserTime + playingExpression.FadeOutTime;
  81. if (playingExpression.ExpressionEndTime == 0.0f || newExpressionEndTime < playingExpression.ExpressionEndTime)
  82. {
  83. playingExpression.ExpressionEndTime = newExpressionEndTime;
  84. }
  85. _playingExpressions[_playingExpressions.Count - 1] = playingExpression;
  86. }
  87. // Fail silently...
  88. if (CurrentExpressionIndex < 0 || CurrentExpressionIndex >= ExpressionsList.CubismExpressionObjects.Length)
  89. {
  90. return;
  91. }
  92. var palyingExpression = CubismPlayingExpression.Create(_model, ExpressionsList.CubismExpressionObjects[CurrentExpressionIndex]);
  93. if(palyingExpression == null)
  94. {
  95. return;
  96. }
  97. // Add to PlayingExList.
  98. _playingExpressions.Add(palyingExpression);
  99. }
  100. /// <summary>
  101. /// Called by cubism update controller. Order to invoke OnLateUpdate.
  102. /// </summary>
  103. public int ExecutionOrder
  104. {
  105. get { return CubismUpdateExecutionOrder.CubismExpressionController; }
  106. }
  107. /// <summary>
  108. /// Called by cubism update controller. Needs to invoke OnLateUpdate on Editing.
  109. /// </summary>
  110. public bool NeedsUpdateOnEditing
  111. {
  112. get { return false; }
  113. }
  114. /// <summary>
  115. /// Called by cubism update manager.
  116. /// </summary>
  117. public void OnLateUpdate()
  118. {
  119. // Fail silently...
  120. if(!enabled || _model == null)
  121. {
  122. return;
  123. }
  124. // Start expression when current expression changed.
  125. if(CurrentExpressionIndex != _lastExpressionIndex)
  126. {
  127. StartExpression();
  128. }
  129. // Update of expressions.
  130. if (UseLegacyBlendCalculation)
  131. {
  132. UpdateExpressionLegacy();
  133. }
  134. else
  135. {
  136. UpdateExpression();
  137. }
  138. }
  139. /// <summary>
  140. /// Update of expressions. (old method)
  141. /// </summary>
  142. private void UpdateExpressionLegacy()
  143. {
  144. // Update expression
  145. for (var expressionIndex = 0; expressionIndex < _playingExpressions.Count; ++expressionIndex)
  146. {
  147. var playingExpression = _playingExpressions[expressionIndex];
  148. UpdateFadeWeight(playingExpression);
  149. // Apply value.
  150. for (var i = 0; i < playingExpression.Destinations.Length; ++i)
  151. {
  152. // Fail silently...
  153. if (playingExpression.Destinations[i] == null)
  154. {
  155. continue;
  156. }
  157. switch (playingExpression.Blend[i])
  158. {
  159. case CubismParameterBlendMode.Additive:
  160. playingExpression.Destinations[i].AddToValue(playingExpression.Value[i], playingExpression.FadeWeight);
  161. break;
  162. case CubismParameterBlendMode.Multiply:
  163. playingExpression.Destinations[i].MultiplyValueBy(playingExpression.Value[i], playingExpression.FadeWeight);
  164. break;
  165. case CubismParameterBlendMode.Override:
  166. playingExpression.Destinations[i].OverrideValue(playingExpression.Destinations[i].Value * (1 - playingExpression.FadeWeight) + (playingExpression.Value[i] * playingExpression.FadeInWeight));
  167. break;
  168. default:
  169. // When an unspecified value is set, it is already in addition mode.
  170. break;
  171. }
  172. }
  173. // Apply update value
  174. _playingExpressions[expressionIndex] = playingExpression;
  175. }
  176. // Remove expression from playing expressions
  177. for (var expressionIndex = _playingExpressions.Count - 1; expressionIndex >= 0; --expressionIndex)
  178. {
  179. if (_playingExpressions[expressionIndex].FadeWeight > 0.0f)
  180. {
  181. continue;
  182. }
  183. _playingExpressions.RemoveAt(expressionIndex);
  184. }
  185. }
  186. /// <summary>
  187. /// Update of expressions.
  188. /// </summary>
  189. private void UpdateExpression()
  190. {
  191. var expressionWeight = 0.0f;
  192. // Update expression
  193. for (var expressionIndex = 0; expressionIndex < _playingExpressions.Count; ++expressionIndex)
  194. {
  195. var playingExpression = _playingExpressions[expressionIndex];
  196. // List all parameters referenced by the Expression being played.
  197. for (var i = 0; i < playingExpression.Destinations.Length; ++i)
  198. {
  199. var index = -1;
  200. // Search for the presence of a parameter ID in the list.
  201. for (var j = 0; j < _expressionParameterValues.Count; j++)
  202. {
  203. if (_expressionParameterValues[j].Parameter != playingExpression.Destinations[i])
  204. {
  205. continue;
  206. }
  207. index = j;
  208. break;
  209. }
  210. if (index >= 0)
  211. {
  212. continue;
  213. }
  214. // If the parameter does not exist in the list, add a new one.
  215. CubismExpressionParameterValue item = new CubismExpressionParameterValue();
  216. item.Parameter = playingExpression.Destinations[i];
  217. if (item.Parameter != null)
  218. {
  219. item.AdditiveValue = DefaultAdditiveValue;
  220. item.MultiplyValue = DefaultMultiplyValue;
  221. item.OverwriteValue = item.Parameter.Value;
  222. _expressionParameterValues.Add(item);
  223. }
  224. }
  225. // ------ Calculate value ------
  226. CalculateExpressionParameters(expressionIndex, playingExpression);
  227. expressionWeight += playingExpression.FadeInTime == 0.0f
  228. ? 1.0f
  229. : CubismFadeMath.GetEasingSine(
  230. (playingExpression.ExpressionUserTime - playingExpression.ExpressionStartTime) /
  231. playingExpression.FadeInTime);
  232. }
  233. // ----- If the latest Expression fade is complete, delete the earlier one. ------
  234. if (_playingExpressions.Count > 1 &&
  235. _playingExpressions[_playingExpressions.Count-1].FadeWeight >= 1.0f)
  236. {
  237. // The last element of the array is not deleted.
  238. for (var i = _playingExpressions.Count - 2; i >= 0; --i)
  239. {
  240. _playingExpressions.RemoveAt(i);
  241. }
  242. }
  243. if (expressionWeight > 1.0f)
  244. {
  245. expressionWeight = 1.0f;
  246. }
  247. // Apply each value to the model.
  248. for (var i = 0; i < _expressionParameterValues.Count; i++)
  249. {
  250. var expressionParameterValue = _expressionParameterValues[i];
  251. expressionParameterValue.Parameter.OverrideValue(
  252. (expressionParameterValue.OverwriteValue + expressionParameterValue.AdditiveValue)
  253. * expressionParameterValue.MultiplyValue,
  254. expressionWeight);
  255. expressionParameterValue.AdditiveValue = DefaultAdditiveValue;
  256. expressionParameterValue.MultiplyValue = DefaultMultiplyValue;
  257. }
  258. }
  259. /// <summary>
  260. /// Update motion weights.
  261. /// </summary>
  262. /// <param name="playingExpression">Expression motion during playback.</param>
  263. private void UpdateFadeWeight(CubismPlayingExpression playingExpression)
  264. {
  265. // Update expression user time.
  266. playingExpression.ExpressionUserTime += Time.deltaTime;
  267. // Update weight
  268. playingExpression.FadeInWeight = (Mathf.Abs(playingExpression.FadeInTime) < float.Epsilon)
  269. ? 1.0f
  270. : CubismFadeMath.GetEasingSine(playingExpression.ExpressionUserTime / playingExpression.FadeInTime);
  271. playingExpression.FadeOutWeight = ((Mathf.Abs(playingExpression.ExpressionEndTime) < float.Epsilon) || (playingExpression.ExpressionEndTime < 0.0f))
  272. ? 1.0f
  273. : CubismFadeMath.GetEasingSine(
  274. (playingExpression.ExpressionEndTime - playingExpression.ExpressionUserTime) / playingExpression.FadeOutTime);
  275. playingExpression.FadeWeight = playingExpression.Weight * playingExpression.FadeInWeight * playingExpression.FadeOutWeight;
  276. }
  277. /// <summary>
  278. /// Calculate parameters related to the model's facial expressions.
  279. /// </summary>
  280. /// <param name="expressionIndex">Index of currently processed facial expression motion.</param>
  281. /// <param name="playingExpression">Expression motion during playback.</param>
  282. private void CalculateExpressionParameters(int expressionIndex, CubismPlayingExpression playingExpression)
  283. {
  284. UpdateFadeWeight(playingExpression);
  285. for (var i = 0; i < _expressionParameterValues.Count; i++)
  286. {
  287. var expressionParameterValue = _expressionParameterValues[i];
  288. if (expressionParameterValue.Parameter == null)
  289. {
  290. continue;
  291. }
  292. var currentParameterValue = expressionParameterValue.OverwriteValue =
  293. expressionParameterValue.Parameter.Value;
  294. var expressionParameters = playingExpression.Destinations;
  295. var parameterIndex = -1;
  296. for (var j = 0; j < expressionParameters.Length; j++)
  297. {
  298. if (expressionParameterValue.Parameter != expressionParameters[j])
  299. {
  300. continue;
  301. }
  302. parameterIndex = j;
  303. break;
  304. }
  305. // Parameters not referenced by the Expression being played have their initial values applied.
  306. if (parameterIndex < 0)
  307. {
  308. if (expressionIndex == 0)
  309. {
  310. expressionParameterValue.AdditiveValue = DefaultAdditiveValue;
  311. expressionParameterValue.MultiplyValue = DefaultMultiplyValue;
  312. expressionParameterValue.OverwriteValue = currentParameterValue;
  313. }
  314. else
  315. {
  316. expressionParameterValue.AdditiveValue =
  317. CalculateValue(
  318. expressionParameterValue.AdditiveValue,
  319. DefaultAdditiveValue,
  320. playingExpression.FadeWeight);
  321. expressionParameterValue.MultiplyValue =
  322. CalculateValue(
  323. expressionParameterValue.MultiplyValue,
  324. DefaultMultiplyValue,
  325. playingExpression.FadeWeight);
  326. expressionParameterValue.OverwriteValue =
  327. CalculateValue(
  328. expressionParameterValue.OverwriteValue,
  329. currentParameterValue,
  330. playingExpression.FadeWeight);
  331. }
  332. _expressionParameterValues[i] = expressionParameterValue;
  333. continue;
  334. }
  335. // Calculate value.
  336. var value = playingExpression.Value[parameterIndex];
  337. float newAdditiveValue, newMultiplyValue, newSetValue;
  338. switch (playingExpression.Blend[parameterIndex])
  339. {
  340. case CubismParameterBlendMode.Additive:
  341. newAdditiveValue = value;
  342. newMultiplyValue = DefaultMultiplyValue;
  343. newSetValue = currentParameterValue;
  344. break;
  345. case CubismParameterBlendMode.Multiply:
  346. newAdditiveValue = DefaultAdditiveValue;
  347. newMultiplyValue = value;
  348. newSetValue = currentParameterValue;
  349. break;
  350. case CubismParameterBlendMode.Override:
  351. newAdditiveValue = DefaultAdditiveValue;
  352. newMultiplyValue = DefaultMultiplyValue;
  353. newSetValue = value;
  354. break;
  355. default:
  356. return;
  357. }
  358. if (expressionIndex == 0)
  359. {
  360. expressionParameterValue.AdditiveValue = newAdditiveValue;
  361. expressionParameterValue.MultiplyValue = newMultiplyValue;
  362. expressionParameterValue.OverwriteValue = newSetValue;
  363. }
  364. else
  365. {
  366. expressionParameterValue.AdditiveValue =
  367. CalculateValue(
  368. expressionParameterValue.AdditiveValue,
  369. newAdditiveValue,
  370. playingExpression.FadeWeight);
  371. expressionParameterValue.MultiplyValue =
  372. CalculateValue(
  373. expressionParameterValue.MultiplyValue,
  374. newMultiplyValue,
  375. playingExpression.FadeWeight);
  376. expressionParameterValue.OverwriteValue =
  377. CalculateValue(
  378. expressionParameterValue.OverwriteValue,
  379. newSetValue,
  380. playingExpression.FadeWeight);
  381. }
  382. _expressionParameterValues[i] = expressionParameterValue;
  383. }
  384. }
  385. /// <summary>
  386. /// Blend calculation.
  387. /// </summary>
  388. /// <param name="source">Source value.</param>
  389. /// <param name="destination">Destination value.</param>
  390. /// <param name="fadeWeight">Weight value.</param>
  391. /// <returns></returns>
  392. private float CalculateValue(float source, float destination, float fadeWeight)
  393. {
  394. return (source * (1.0f - fadeWeight)) + (destination * fadeWeight);
  395. }
  396. #region Unity Event Handling
  397. /// <summary>
  398. /// Called by Unity.
  399. /// </summary>
  400. private void OnEnable()
  401. {
  402. _model = this.FindCubismModel();
  403. // Get cubism update controller.
  404. HasUpdateController = (GetComponent<CubismUpdateController>() != null);
  405. }
  406. /// <summary>
  407. /// Called by Unity.
  408. /// </summary>
  409. private void LateUpdate()
  410. {
  411. if(!HasUpdateController)
  412. {
  413. OnLateUpdate();
  414. }
  415. }
  416. #endregion
  417. }
  418. }