/** * 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 UnityEngine; namespace Live2D.Cubism.Framework { /// /// Automatic mouth movement. /// public sealed class CubismAutoEyeBlinkInput : MonoBehaviour { /// /// Mean time between eye blinks in seconds. /// [SerializeField, Range(1f, 10f)] public float Mean = 2.5f; /// /// Maximum deviation from in seconds. /// [SerializeField, Range(0.5f, 5f)] public float MaximumDeviation = 2f; /// /// Timescale. /// [SerializeField, Range(1f, 20f)] public float Timescale = 10f; /// /// Target controller. /// private CubismEyeBlinkController Controller { get; set; } /// /// Time until next eye blink. /// private float T { get; set; } /// /// Control over whether output should be evaluated. /// private Phase CurrentPhase { get; set; } /// /// Used for switching from to and back to . /// private float LastValue { get; set; } /// /// Resets the input. /// public void Reset() { T = 0f; } #region Unity Event Handling /// /// Called by Unity. Initializes input. /// private void Start() { Controller = GetComponent(); } /// /// Called by Unity. Updates controller. /// /// /// Make sure this method is called after any animations are evaluated. /// private void LateUpdate() { // Fail silently. if (Controller == null) { return; } // Wait for time until blink. if (CurrentPhase == Phase.Idling) { T -= Time.deltaTime; if (T < 0f) { T = (Mathf.PI * -0.5f); LastValue = 1f; CurrentPhase = Phase.ClosingEyes; } else { return; } } // Evaluate eye blinking. T += (Time.deltaTime * Timescale); var value = Mathf.Abs(Mathf.Sin(T)); if (CurrentPhase == Phase.ClosingEyes && value > LastValue) { CurrentPhase = Phase.OpeningEyes; } else if (CurrentPhase == Phase.OpeningEyes && value < LastValue) { value = 1f; CurrentPhase = Phase.Idling; T = Mean + Random.Range(-MaximumDeviation, MaximumDeviation); } Controller.EyeOpening = value; LastValue = value; } #endregion /// /// Internal states. /// private enum Phase { /// /// Idle state. /// Idling, /// /// State when closing eyes. /// ClosingEyes, /// /// State when opening eyes. /// OpeningEyes } } }