/** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */ using Live2D.Cubism.Core; using Live2D.Cubism.Framework.MotionFade; using System.Collections.Generic; using UnityEngine; namespace Live2D.Cubism.Framework.Expression { /// /// Expression controller. /// public class CubismExpressionController : MonoBehaviour, ICubismUpdatable { #region variable /// /// Expressions data list. /// [SerializeField] public CubismExpressionList ExpressionsList; /// /// CubismModel cache. /// private CubismModel _model = null; /// /// Playing expressions. /// private List _playingExpressions = new List(); /// /// Playing expressions index. /// [SerializeField] public int CurrentExpressionIndex = -1; /// /// Last playing expressions index. /// private int _lastExpressionIndex = -1; /// /// Model has update controller component. /// [HideInInspector] public bool HasUpdateController { get; set; } #endregion /// /// Add new expression to playing expressions. /// private void StartExpression() { // Fail silently... if(ExpressionsList == null || ExpressionsList.CubismExpressionObjects == null) { return; } // Backup expression. _lastExpressionIndex = CurrentExpressionIndex; // Set last expression end time if(_playingExpressions.Count > 0) { var playingExpression = _playingExpressions[_playingExpressions.Count - 1]; playingExpression.ExpressionEndTime = playingExpression.ExpressionUserTime + playingExpression.FadeOutTime; _playingExpressions[_playingExpressions.Count - 1] = playingExpression; } // Fail silently... if(CurrentExpressionIndex < 0 || CurrentExpressionIndex >= ExpressionsList.CubismExpressionObjects.Length) { return; } var palyingExpression = CubismPlayingExpression.Create(_model, ExpressionsList.CubismExpressionObjects[CurrentExpressionIndex]); if(palyingExpression == null) { return; } // Add to PlayingExList. _playingExpressions.Add(palyingExpression); } /// /// Called by cubism update controller. Order to invoke OnLateUpdate. /// public int ExecutionOrder { get { return CubismUpdateExecutionOrder.CubismExpressionController; } } /// /// Called by cubism update controller. Needs to invoke OnLateUpdate on Editing. /// public bool NeedsUpdateOnEditing { get { return false; } } /// /// Called by cubism update manager. /// public void OnLateUpdate() { // Fail silently... if(!enabled || _model == null) { return; } // Start expression when current expression changed. if(CurrentExpressionIndex != _lastExpressionIndex) { StartExpression(); } // Update expression for(var expressionIndex = 0; expressionIndex < _playingExpressions.Count; ++expressionIndex) { var playingExpression = _playingExpressions[expressionIndex]; // Update expression user time. playingExpression.ExpressionUserTime += Time.deltaTime; // Update weight var fadeIn = (Mathf.Abs(playingExpression.FadeInTime) < float.Epsilon) ? 1.0f : CubismFadeMath.GetEasingSine(playingExpression.ExpressionUserTime / playingExpression.FadeInTime); var fadeOut = ((Mathf.Abs(playingExpression.ExpressionEndTime) < float.Epsilon) || (playingExpression.ExpressionEndTime < 0.0f)) ? 1.0f : CubismFadeMath.GetEasingSine( (playingExpression.ExpressionEndTime - playingExpression.ExpressionUserTime) / playingExpression.FadeOutTime); playingExpression.Weight = fadeIn * fadeOut; // Apply value. for(var i = 0; i < playingExpression.Destinations.Length; ++i) { // Fail silently... if(playingExpression.Destinations[i] == null) { continue; } switch(playingExpression.Blend[i]) { case CubismParameterBlendMode.Additive: playingExpression.Destinations[i].AddToValue(playingExpression.Value[i], playingExpression.Weight); break; case CubismParameterBlendMode.Multiply: playingExpression.Destinations[i].MultiplyValueBy(playingExpression.Value[i], playingExpression.Weight); break; case CubismParameterBlendMode.Override: playingExpression.Destinations[i].Value = playingExpression.Destinations[i].Value * (1 - playingExpression.Weight) + (playingExpression.Value[i] * playingExpression.Weight); break; default: // When an unspecified value is set, it is already in addition mode. break; } } // Apply update value _playingExpressions[expressionIndex] = playingExpression; } // Remove expression from playing expressions for(var expressionIndex = _playingExpressions.Count - 1; expressionIndex >= 0; --expressionIndex) { if(_playingExpressions[expressionIndex].Weight > 0.0f) { continue; } _playingExpressions.RemoveAt(expressionIndex); } } #region Unity Event Handling /// /// Called by Unity. /// private void OnEnable() { _model = this.FindCubismModel(); // Get cubism update controller. HasUpdateController = (GetComponent() != null); } /// /// Called by Unity. /// private void LateUpdate() { if(!HasUpdateController) { OnLateUpdate(); } } #endregion } }