/**
* 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
}
}
}