live2D (sdk가 6.5 미지원으로 sprite로 대응)
This commit is contained in:
@@ -0,0 +1,447 @@
|
||||
/**
|
||||
* 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.Motion;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
/// <summary>
|
||||
/// Cubism fade controller.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class CubismFadeController : MonoBehaviour, ICubismUpdatable
|
||||
{
|
||||
#region Variable
|
||||
|
||||
/// <summary>
|
||||
/// Cubism fade motion list.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismFadeMotionList CubismFadeMotionList;
|
||||
|
||||
/// <summary>
|
||||
/// Parameters cache.
|
||||
/// </summary>
|
||||
private CubismParameter[] DestinationParameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Parts cache.
|
||||
/// </summary>
|
||||
private CubismPart[] DestinationParts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Model has motion controller component.
|
||||
/// </summary>
|
||||
private CubismMotionController _motionController;
|
||||
|
||||
/// <summary>
|
||||
/// Model has cubism update controller component.
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public bool HasUpdateController { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fade state machine behavior set in the animator.
|
||||
/// </summary>
|
||||
private ICubismFadeState[] _fadeStates;
|
||||
|
||||
/// <summary>
|
||||
/// Model has animator component.
|
||||
/// </summary>
|
||||
private Animator _animator;
|
||||
|
||||
/// <summary>
|
||||
/// Restore parameter value.
|
||||
/// </summary>
|
||||
private CubismParameterStore _parameterStore;
|
||||
|
||||
/// <summary>
|
||||
/// Fading flags for each layer.
|
||||
/// </summary>
|
||||
private bool[] _isFading;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Function
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the controller. Call this method after adding and/or removing <see cref="CubismFadeParameter"/>s.
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
|
||||
// Fail silently...
|
||||
if (_animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DestinationParameters = this.FindCubismModel().Parameters;
|
||||
DestinationParts = this.FindCubismModel().Parts;
|
||||
_motionController = GetComponent<CubismMotionController>();
|
||||
_parameterStore = GetComponent<CubismParameterStore>();
|
||||
|
||||
// Get cubism update controller.
|
||||
HasUpdateController = (GetComponent<CubismUpdateController>() != null);
|
||||
|
||||
_fadeStates = (ICubismFadeState[])_animator.GetBehaviours<CubismFadeStateObserver>();
|
||||
|
||||
if ((_fadeStates == null || _fadeStates.Length == 0) && _motionController != null)
|
||||
{
|
||||
_fadeStates = _motionController.GetFadeStates();
|
||||
}
|
||||
|
||||
if (_fadeStates == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isFading = new bool[_fadeStates.Length];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by cubism update controller. Order to invoke OnLateUpdate.
|
||||
/// </summary>
|
||||
public int ExecutionOrder
|
||||
{
|
||||
get { return CubismUpdateExecutionOrder.CubismFadeController; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by cubism update controller. Needs to invoke OnLateUpdate on Editing.
|
||||
/// </summary>
|
||||
public bool NeedsUpdateOnEditing
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by cubism update controller. Updates controller.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Make sure this method is called after any animations are evaluated.
|
||||
/// </remarks>
|
||||
public void OnLateUpdate()
|
||||
{
|
||||
// Fail silently.
|
||||
if (!enabled || _fadeStates == null || _parameterStore == null
|
||||
|| DestinationParameters == null || DestinationParts == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var time = Time.time;
|
||||
for (var i = 0; i < _fadeStates.Length; ++i)
|
||||
{
|
||||
_isFading[i] = false;
|
||||
|
||||
var playingMotions = _fadeStates[i].GetPlayingMotions();
|
||||
if (playingMotions == null || playingMotions.Count <= 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var latestPlayingMotion = playingMotions[playingMotions.Count - 1];
|
||||
|
||||
var playingMotionData = latestPlayingMotion.Motion;
|
||||
var elapsedTime = time - latestPlayingMotion.FadeInStartTime;
|
||||
for (var j = 0; j < playingMotionData.ParameterFadeInTimes.Length; j++)
|
||||
{
|
||||
if ((elapsedTime <= playingMotionData.FadeInTime) ||
|
||||
((0 <= playingMotionData.ParameterFadeInTimes[j]) &&
|
||||
(elapsedTime <= playingMotionData.ParameterFadeInTimes[j])) ||
|
||||
!_fadeStates[i].GetStateTransitionFinished())
|
||||
{
|
||||
_isFading[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isFadingAllFinished = true;
|
||||
for (var i = 0; i < _fadeStates.Length; ++i)
|
||||
{
|
||||
if (_isFading[i])
|
||||
{
|
||||
isFadingAllFinished = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
var playingMotions = _fadeStates[i].GetPlayingMotions();
|
||||
for (var j = playingMotions.Count - 2; j >= 0; --j)
|
||||
{
|
||||
var playingMotion = playingMotions[j];
|
||||
if (time <= playingMotion.EndTime)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If fade-in has been completed, delete the motion that has been played back.
|
||||
_fadeStates[i].StopAnimation(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (isFadingAllFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parameterStore.RestoreParameters();
|
||||
|
||||
|
||||
// Update sources and destinations.
|
||||
for (var i = 0; i < _fadeStates.Length; ++i)
|
||||
{
|
||||
if (!_isFading[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UpdateFade(_fadeStates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update motion fade.
|
||||
/// </summary>
|
||||
/// <param name="fadeState">Fade state observer.</param>
|
||||
private void UpdateFade(ICubismFadeState fadeState)
|
||||
{
|
||||
var playingMotions = fadeState.GetPlayingMotions();
|
||||
|
||||
if (playingMotions == null)
|
||||
{
|
||||
// Do not process if there is only one motion, if it does not switch.
|
||||
return;
|
||||
}
|
||||
|
||||
// Weight set for the layer being processed.
|
||||
// (In the case of the layer located at the top, it is forced to 1.)
|
||||
var layerWeight = fadeState.GetLayerWeight();
|
||||
|
||||
var time = Time.time;
|
||||
|
||||
// Calculate MotionFade.
|
||||
for (var i = 0; i < playingMotions.Count; i++)
|
||||
{
|
||||
var playingMotion = playingMotions[i];
|
||||
|
||||
var fadeMotion = playingMotion.Motion;
|
||||
if (fadeMotion == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var elapsedTime = time - playingMotion.FadeInStartTime;
|
||||
var endTime = playingMotion.EndTime - elapsedTime;
|
||||
|
||||
var fadeInTime = fadeMotion.FadeInTime;
|
||||
var fadeOutTime = fadeMotion.FadeOutTime;
|
||||
|
||||
|
||||
var fadeInWeight = (fadeInTime <= 0.0f)
|
||||
? 1.0f
|
||||
: CubismFadeMath.GetEasingSine(elapsedTime / fadeInTime);
|
||||
var fadeOutWeight = (fadeOutTime <= 0.0f || playingMotion.EndTime < 0.0f)
|
||||
? 1.0f
|
||||
: CubismFadeMath.GetEasingSine((playingMotion.EndTime - time) / fadeOutTime);
|
||||
|
||||
|
||||
playingMotions[i] = playingMotion;
|
||||
|
||||
var motionWeight = fadeInWeight * fadeOutWeight * layerWeight;
|
||||
|
||||
// Apply to parameter values
|
||||
for (var j = 0; j < DestinationParameters.Length; ++j)
|
||||
{
|
||||
var index = -1;
|
||||
for (var k = 0; k < fadeMotion.ParameterIds.Length; ++k)
|
||||
{
|
||||
if (fadeMotion.ParameterIds[k] != DestinationParameters[j].Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
index = k;
|
||||
break;
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
// There is not target ID curve in motion.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var value = fadeMotion.ParameterCurves[index].Evaluate(elapsedTime);
|
||||
|
||||
if (DestinationParameters[j].IsRepeat())
|
||||
{
|
||||
value = DestinationParameters[j].GetParameterRepeatValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = DestinationParameters[j].GetParameterClampValue(value);
|
||||
}
|
||||
|
||||
value = Evaluate(
|
||||
value, elapsedTime, endTime,
|
||||
fadeInWeight, fadeOutWeight,
|
||||
fadeMotion.ParameterFadeInTimes[index], fadeMotion.ParameterFadeOutTimes[index],
|
||||
motionWeight, DestinationParameters[j].Value);
|
||||
|
||||
|
||||
DestinationParameters[j].OverrideValue(value);
|
||||
}
|
||||
|
||||
// Apply to part opacities
|
||||
for (var j = 0; j < DestinationParts.Length; ++j)
|
||||
{
|
||||
var index = -1;
|
||||
for (var k = 0; k < fadeMotion.ParameterIds.Length; ++k)
|
||||
{
|
||||
if (fadeMotion.ParameterIds[k] != DestinationParts[j].Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
index = k;
|
||||
break;
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
// There is not target ID curve in motion.
|
||||
continue;
|
||||
}
|
||||
|
||||
DestinationParts[j].Opacity = Evaluate(
|
||||
fadeMotion.ParameterCurves[index], elapsedTime, endTime,
|
||||
fadeInWeight, fadeOutWeight,
|
||||
fadeMotion.ParameterFadeInTimes[index], fadeMotion.ParameterFadeOutTimes[index],
|
||||
motionWeight, DestinationParts[j].Opacity);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate fade curve.
|
||||
/// </summary>
|
||||
/// <param name="curve">Curves to be evaluated.</param>
|
||||
/// <param name="elapsedTime">Elapsed Time.</param>
|
||||
/// <param name="endTime">Fading end time.</param>
|
||||
/// <param name="fadeInTime">Fade in time.</param>
|
||||
/// <param name="fadeOutTime">Fade out time.</param>
|
||||
/// <param name="parameterFadeInTime">Fade in time parameter.</param>
|
||||
/// <param name="parameterFadeOutTime">Fade out time parameter.</param>
|
||||
/// <param name="motionWeight">Motion weight.</param>
|
||||
/// <param name="currentValue">Current value with weight applied.</param>
|
||||
public float Evaluate(
|
||||
AnimationCurve curve, float elapsedTime, float endTime,
|
||||
float fadeInTime, float fadeOutTime,
|
||||
float parameterFadeInTime, float parameterFadeOutTime,
|
||||
float motionWeight, float currentValue)
|
||||
{
|
||||
if (curve.length <= 0)
|
||||
{
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
// Motion fade.
|
||||
return Evaluate(
|
||||
curve.Evaluate(elapsedTime), elapsedTime, endTime,
|
||||
fadeInTime, fadeOutTime,
|
||||
parameterFadeInTime, parameterFadeOutTime,
|
||||
motionWeight, currentValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate fade value.
|
||||
/// </summary>
|
||||
/// <param name="value">New value.</param>
|
||||
/// <param name="elapsedTime">Elapsed Time.</param>
|
||||
/// <param name="endTime">Fading end time.</param>
|
||||
/// <param name="fadeInTime">Fade in time.</param>
|
||||
/// <param name="fadeOutTime">Fade out time.</param>
|
||||
/// <param name="parameterFadeInTime">Fade in time parameter.</param>
|
||||
/// <param name="parameterFadeOutTime">Fade out time parameter.</param>
|
||||
/// <param name="motionWeight">Motion weight.</param>
|
||||
/// <param name="currentValue">Current value with weight applied.</param>
|
||||
public float Evaluate(
|
||||
float value, float elapsedTime, float endTime,
|
||||
float fadeInTime, float fadeOutTime,
|
||||
float parameterFadeInTime, float parameterFadeOutTime,
|
||||
float motionWeight, float currentValue)
|
||||
{
|
||||
|
||||
// Motion fade.
|
||||
if (parameterFadeInTime < 0.0f &&
|
||||
parameterFadeOutTime < 0.0f)
|
||||
{
|
||||
return currentValue + (value - currentValue) * motionWeight;
|
||||
}
|
||||
|
||||
// Parameter fade.
|
||||
float fadeInWeight, fadeOutWeight;
|
||||
if (parameterFadeInTime < 0.0f)
|
||||
{
|
||||
fadeInWeight = fadeInTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeInWeight = (parameterFadeInTime < float.Epsilon)
|
||||
? 1.0f
|
||||
: CubismFadeMath.GetEasingSine(elapsedTime / parameterFadeInTime);
|
||||
}
|
||||
|
||||
if (parameterFadeOutTime < 0.0f)
|
||||
{
|
||||
fadeOutWeight = fadeOutTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeOutWeight = (parameterFadeOutTime < float.Epsilon || (endTime < 0.0f))
|
||||
? 1.0f
|
||||
: CubismFadeMath.GetEasingSine(endTime / parameterFadeOutTime);
|
||||
}
|
||||
|
||||
var parameterWeight = fadeInWeight * fadeOutWeight;
|
||||
|
||||
return currentValue + (value - currentValue) * parameterWeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity Events Handling
|
||||
|
||||
/// <summary>
|
||||
/// Initializes instance.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
// Initialize cache.
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Unity.
|
||||
/// </summary>
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!HasUpdateController)
|
||||
{
|
||||
OnLateUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cd9e6647bfff7542acb0200ab74bdd1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
public enum CubismFadeCurveType
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameter.
|
||||
/// </summary>
|
||||
Parameter,
|
||||
|
||||
/// <summary>
|
||||
/// Part opacity.
|
||||
/// </summary>
|
||||
Part
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47af690fba051ca428c5e5ee69068b28
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Assets/Live2D/Cubism/Framework/MotionFade/CubismFadeMath.cs
Normal file
29
Assets/Live2D/Cubism/Framework/MotionFade/CubismFadeMath.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 System;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
public static class CubismFadeMath
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculate the easing processed signaure.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be subjected to easing.</param>
|
||||
/// <returns>Eased sign value.</returns>
|
||||
public static float GetEasingSine(float value)
|
||||
{
|
||||
if (value < 0.0f) return 0.0f;
|
||||
if (value > 1.0f) return 1.0f;
|
||||
|
||||
return (float)(0.5f - 0.5f * Math.Cos(value * (float)Math.PI));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4508bdfe290c2a44858dbe185724e76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* 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;
|
||||
using Live2D.Cubism.Framework.Json;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
public class CubismFadeMotionData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of motion.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public string MotionName;
|
||||
|
||||
/// <summary>
|
||||
/// Store time to fade in from .model3.json.
|
||||
/// NOTE: It is used to save `FadeInTime` from .model3.json. Please use <see cref="FadeInTime"/> instead of using it directly.
|
||||
/// </summary>
|
||||
[HideInInspector, SerializeField]
|
||||
public float ModelFadeInTime = -1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Store time to fade out from .model3.json.
|
||||
/// NOTE: It is used to save `FadeOutTime` from .model3.json. Please use <see cref="FadeOutTime"/> instead of using it directly.
|
||||
/// </summary>
|
||||
[HideInInspector, SerializeField]
|
||||
public float ModelFadeOutTime = -1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Time to fade in.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float FadeInTime;
|
||||
|
||||
/// <summary>
|
||||
/// Time to fade out.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float FadeOutTime;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter ids.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public string[] ParameterIds;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter curves.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public AnimationCurve[] ParameterCurves;
|
||||
|
||||
/// <summary>
|
||||
/// Fade in time parameters.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float[] ParameterFadeInTimes;
|
||||
|
||||
/// <summary>
|
||||
/// Fade out time parameters.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float[] ParameterFadeOutTimes;
|
||||
|
||||
/// <summary>
|
||||
/// Motion length.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float MotionLength;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create CubismFadeMotionData from CubismMotion3Json.
|
||||
/// </summary>
|
||||
/// <param name="motion3Json">Motion3json as the creator.</param>
|
||||
/// <param name="motionName">Motion name of interest.</param>
|
||||
/// <param name="motionLength">Length of target motion.</param>
|
||||
/// <param name="shouldImportAsOriginalWorkflow">Whether the original work flow or not.</param>
|
||||
/// <param name="isCallFromModelJson">Whether it is a call from the model json.</param>
|
||||
/// <param name="model3Json">.model3.json to retrieve the fade time.</param>
|
||||
/// <returns>Fade data created based on motion3json.</returns>
|
||||
public static CubismFadeMotionData CreateInstance(
|
||||
CubismMotion3Json motion3Json, string motionName, float motionLength,
|
||||
bool shouldImportAsOriginalWorkflow = false, bool isCallFromModelJson = false, CubismModel3Json model3Json = null)
|
||||
{
|
||||
var fadeMotion = CreateInstance<CubismFadeMotionData>();
|
||||
var curveCount = motion3Json.Curves.Length;
|
||||
fadeMotion.ParameterIds = new string[curveCount];
|
||||
fadeMotion.ParameterFadeInTimes = new float[curveCount];
|
||||
fadeMotion.ParameterFadeOutTimes = new float[curveCount];
|
||||
fadeMotion.ParameterCurves = new AnimationCurve[curveCount];
|
||||
|
||||
return CreateInstance(fadeMotion, motion3Json, motionName, motionLength, shouldImportAsOriginalWorkflow, isCallFromModelJson, model3Json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put motion3json's fade information back into fade motion data.
|
||||
/// </summary>
|
||||
/// <param name="fadeMotion">Instance containing fade information.</param>
|
||||
/// <param name="motion3Json">Target motion3json.</param>
|
||||
/// <param name="motionName">Motion name of interest.</param>
|
||||
/// <param name="motionLength">Motion length.</param>
|
||||
/// <param name="shouldImportAsOriginalWorkflow">Whether the original work flow or not.</param>
|
||||
/// <param name="isCallFormModelJson">Whether it is a call from the model json.</param>
|
||||
/// <param name="model3Json">.model3.json to retrieve the fade time.</param>
|
||||
/// <returns>Fade data created based on fademotiondata.</returns>
|
||||
public static CubismFadeMotionData CreateInstance(
|
||||
CubismFadeMotionData fadeMotion, CubismMotion3Json motion3Json, string motionName, float motionLength,
|
||||
bool shouldImportAsOriginalWorkflow = false, bool isCallFormModelJson = false, CubismModel3Json model3Json = null)
|
||||
{
|
||||
if (model3Json != null)
|
||||
{
|
||||
GetFadeDataFromModel3Json(model3Json, fadeMotion);
|
||||
}
|
||||
|
||||
if (motion3Json == null)
|
||||
{
|
||||
return fadeMotion;
|
||||
}
|
||||
|
||||
fadeMotion.MotionName = motionName;
|
||||
fadeMotion.MotionLength = motionLength;
|
||||
|
||||
if (fadeMotion.ModelFadeInTime < 0.0f)
|
||||
{
|
||||
fadeMotion.FadeInTime = (motion3Json.Meta.FadeInTime < 0.0f) ? 1.0f : motion3Json.Meta.FadeInTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeMotion.FadeInTime = fadeMotion.ModelFadeInTime;
|
||||
}
|
||||
|
||||
if (fadeMotion.ModelFadeOutTime < 0.0f)
|
||||
{
|
||||
fadeMotion.FadeOutTime = (motion3Json.Meta.FadeOutTime < 0.0f) ? 1.0f : motion3Json.Meta.FadeOutTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeMotion.FadeOutTime = fadeMotion.ModelFadeOutTime;
|
||||
}
|
||||
|
||||
for (var i = 0; i < motion3Json.Curves.Length; ++i)
|
||||
{
|
||||
var curve = motion3Json.Curves[i];
|
||||
|
||||
// In original workflow mode, skip add part opacity curve when call not from model3.json.
|
||||
if (curve.Target == "PartOpacity" && shouldImportAsOriginalWorkflow && !isCallFormModelJson)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fadeMotion.ParameterIds[i] = curve.Id;
|
||||
fadeMotion.ParameterFadeInTimes[i] = (curve.FadeInTime < 0.0f) ? -1.0f : curve.FadeInTime;
|
||||
fadeMotion.ParameterFadeOutTimes[i] = (curve.FadeOutTime < 0.0f) ? -1.0f : curve.FadeOutTime;
|
||||
fadeMotion.ParameterCurves[i] = new AnimationCurve(CubismMotion3Json.ConvertCurveSegmentsToKeyframes(curve.Segments));
|
||||
}
|
||||
|
||||
return fadeMotion;
|
||||
}
|
||||
|
||||
private static void GetFadeDataFromModel3Json(CubismModel3Json modelJson, CubismFadeMotionData fadeMotion)
|
||||
{
|
||||
var motions = modelJson.FileReferences.Motions.Motions;
|
||||
|
||||
for (var groupIndex = 0; groupIndex < motions?.Length; groupIndex++)
|
||||
{
|
||||
if (motions[groupIndex] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var motionIndex = 0; motionIndex < motions[groupIndex]?.Length; motionIndex++)
|
||||
{
|
||||
var motion = motions[groupIndex][motionIndex];
|
||||
|
||||
// Set FadeInTime.
|
||||
if (!(motion.FadeInTime < 0.0f))
|
||||
{
|
||||
fadeMotion.ModelFadeInTime = motion.FadeInTime;
|
||||
fadeMotion.FadeInTime = fadeMotion.ModelFadeInTime;
|
||||
}
|
||||
|
||||
// Set FadeOutTime.
|
||||
if (!(motion.FadeOutTime < 0.0f))
|
||||
{
|
||||
fadeMotion.ModelFadeOutTime = motion.FadeOutTime;
|
||||
fadeMotion.FadeInTime = fadeMotion.ModelFadeInTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f1ee1adc36a8a04a8d7c42ac5d6bc27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.MotionFade
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Live2D Cubism/Fade Motion List")]
|
||||
public class CubismFadeMotionList : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Cubism fade motion instance ids.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public int[] MotionInstanceIds;
|
||||
|
||||
/// <summary>
|
||||
/// Cubism fade motion objects.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismFadeMotionData[] CubismFadeMotionObjects;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 403ae2dd693bb1d4b924f6b8d206b053
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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 System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
public struct CubismFadePlayingMotion
|
||||
{
|
||||
/// <summary>
|
||||
/// Animation clip start time.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// Animation clip end time.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float EndTime;
|
||||
|
||||
/// <summary>
|
||||
/// Cubism fade in start time.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public float FadeInStartTime;
|
||||
|
||||
/// <summary>
|
||||
/// Animation playing speed.
|
||||
/// </summary>
|
||||
[SerializeField, Range(0.0f, float.MaxValue)]
|
||||
public float Speed;
|
||||
|
||||
/// <summary>
|
||||
/// Cubism fade motion data.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public CubismFadeMotionData Motion;
|
||||
|
||||
/// <summary>
|
||||
/// Is animation loop.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public bool IsLooping;
|
||||
|
||||
/// <summary>
|
||||
/// Motion weight.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public float Weight;
|
||||
|
||||
/// <summary>
|
||||
/// Clip event <see cref="CubismFadeMotionData"/> InstanceId.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public int? InstanceId;
|
||||
|
||||
/// <summary>
|
||||
/// Is animation end event invoked.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public bool IsAnimationEndEventInvoked;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71820e64bc297764c8a2d11a31cff80f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* 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 System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
public class CubismFadeStateObserver : StateMachineBehaviour, ICubismFadeState
|
||||
{
|
||||
#region variable
|
||||
|
||||
/// <summary>
|
||||
/// Cubism fade motion list.
|
||||
/// </summary>
|
||||
private CubismFadeMotionList _cubismFadeMotionList;
|
||||
|
||||
/// <summary>
|
||||
/// Cubism playing motion list.
|
||||
/// </summary>
|
||||
private List<CubismFadePlayingMotion> _playingMotions;
|
||||
|
||||
/// <summary>
|
||||
/// State that attached this is default.
|
||||
/// </summary>
|
||||
private bool _isDefaulState;
|
||||
|
||||
/// <summary>
|
||||
/// Layer index that attached this.
|
||||
/// </summary>
|
||||
private int _layerIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Weight of layer that attached this.
|
||||
/// </summary>
|
||||
private float _layerWeight;
|
||||
|
||||
/// <summary>
|
||||
/// State that attached this is transition finished.
|
||||
/// </summary>
|
||||
private bool _isStateTransitionFinished;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Fade State Interface
|
||||
|
||||
/// <summary>
|
||||
/// Get cubism playing motion list.
|
||||
/// </summary>
|
||||
/// <returns>Cubism playing motion list.</returns>
|
||||
public List<CubismFadePlayingMotion> GetPlayingMotions()
|
||||
{
|
||||
return _playingMotions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is default state.
|
||||
/// </summary>
|
||||
/// <returns><see langword="true"/> State is default; <see langword="false"/> otherwise.</returns>
|
||||
public bool IsDefaultState()
|
||||
{
|
||||
return _isDefaulState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get layer weight.
|
||||
/// </summary>
|
||||
/// <returns>Layer weight.</returns>
|
||||
public float GetLayerWeight()
|
||||
{
|
||||
return _layerWeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get state transition finished.
|
||||
/// </summary>
|
||||
/// <returns><see langword="true"/> State transition is finished; <see langword="false"/> otherwise.</returns>
|
||||
public bool GetStateTransitionFinished()
|
||||
{
|
||||
return _isStateTransitionFinished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set state transition finished.
|
||||
/// </summary>
|
||||
/// <param name="isFinished">State is finished.</param>
|
||||
public void SetStateTransitionFinished(bool isFinished)
|
||||
{
|
||||
_isStateTransitionFinished = isFinished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop animation.
|
||||
/// </summary>
|
||||
/// <param name="index">Playing motion index.</param>
|
||||
public void StopAnimation(int index)
|
||||
{
|
||||
_playingMotions.RemoveAt(index);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Unity Event Handling
|
||||
|
||||
/// <summary>
|
||||
/// Called by Unity.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_isStateTransitionFinished = false;
|
||||
|
||||
if (_playingMotions == null)
|
||||
{
|
||||
_playingMotions = new List<CubismFadePlayingMotion>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Unity.
|
||||
/// </summary>
|
||||
/// <param name="animator">Animator.</param>
|
||||
/// <param name="stateInfo">Animator state info.</param>
|
||||
/// <param name="layerIndex">Index of the layer.</param>
|
||||
/// <param name="controller">Animation controller playable.</param>
|
||||
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
|
||||
{
|
||||
var fadeController = animator.gameObject.GetComponent<CubismFadeController>();
|
||||
|
||||
// Fail silently...
|
||||
if (fadeController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cubismFadeMotionList = fadeController.CubismFadeMotionList;
|
||||
_isStateTransitionFinished = false;
|
||||
|
||||
_layerIndex = layerIndex;
|
||||
_layerWeight = (_layerIndex == 0)
|
||||
? 1.0f
|
||||
: animator.GetLayerWeight(_layerIndex);
|
||||
|
||||
var animatorClipInfo = controller.GetNextAnimatorClipInfo(layerIndex);
|
||||
|
||||
_isDefaulState = (animatorClipInfo.Length == 0);
|
||||
|
||||
if (_isDefaulState)
|
||||
{
|
||||
// Get the motion of Default State only for the first time.
|
||||
animatorClipInfo = controller.GetCurrentAnimatorClipInfo(layerIndex);
|
||||
}
|
||||
|
||||
// Set playing motions end time.
|
||||
if ((_playingMotions.Count > 0) && (_playingMotions[_playingMotions.Count - 1].Motion != null))
|
||||
{
|
||||
var motion = _playingMotions[_playingMotions.Count - 1];
|
||||
|
||||
var time = Time.time;
|
||||
|
||||
var newEndTime = time + motion.Motion.FadeOutTime;
|
||||
|
||||
if (motion.EndTime < 0.0f || newEndTime < motion.EndTime)
|
||||
{
|
||||
motion.EndTime = newEndTime;
|
||||
}
|
||||
|
||||
while (motion.IsLooping)
|
||||
{
|
||||
if ((motion.StartTime + motion.Motion.MotionLength) >= time)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
motion.StartTime += motion.Motion.MotionLength;
|
||||
}
|
||||
|
||||
|
||||
_playingMotions[_playingMotions.Count - 1] = motion;
|
||||
}
|
||||
|
||||
for (var i = 0; i < animatorClipInfo.Length; ++i)
|
||||
{
|
||||
CubismFadePlayingMotion playingMotion;
|
||||
|
||||
|
||||
var instanceId = -1;
|
||||
var events = animatorClipInfo[i].clip.events;
|
||||
for(var k = 0; k < events.Length; ++k)
|
||||
{
|
||||
if(events[k].functionName != "InstanceId")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
instanceId = events[k].intParameter;
|
||||
break;
|
||||
}
|
||||
|
||||
var motionIndex = -1;
|
||||
for (var j = 0; j < _cubismFadeMotionList.MotionInstanceIds.Length; ++j)
|
||||
{
|
||||
if (_cubismFadeMotionList.MotionInstanceIds[j] != instanceId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
motionIndex = j;
|
||||
break;
|
||||
}
|
||||
|
||||
playingMotion.Motion = (motionIndex == -1)
|
||||
? null
|
||||
: _cubismFadeMotionList.CubismFadeMotionObjects[motionIndex];
|
||||
|
||||
playingMotion.Speed = 1.0f;
|
||||
playingMotion.StartTime = Time.time;
|
||||
playingMotion.FadeInStartTime = Time.time;
|
||||
playingMotion.EndTime = -1.0f;
|
||||
playingMotion.IsLooping = animatorClipInfo[i].clip.isLooping;
|
||||
playingMotion.Weight = 0.0f;
|
||||
playingMotion.InstanceId = instanceId;
|
||||
playingMotion.IsAnimationEndEventInvoked = false;
|
||||
|
||||
_playingMotions.Add(playingMotion);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by Unity.
|
||||
/// </summary>
|
||||
/// <param name="animator">Animator.</param>
|
||||
/// <param name="stateInfo">Animator state info.</param>
|
||||
/// <param name="layerIndex">Index of the layer.</param>
|
||||
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
|
||||
{
|
||||
_isStateTransitionFinished = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2df377c5758f8974aaed292833ec3ba0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Live2D/Cubism/Framework/MotionFade/Editor.meta
Normal file
8
Assets/Live2D/Cubism/Framework/MotionFade/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d1c056cbe0af0e41b9ee3a919e16b58
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,408 @@
|
||||
/**
|
||||
* 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.Editor;
|
||||
using Live2D.Cubism.Editor.Importers;
|
||||
using Live2D.Cubism.Framework.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
internal static class CubismFadeMotionImporter
|
||||
{
|
||||
#region Unity Event Handling
|
||||
|
||||
/// <summary>
|
||||
/// Register fadeMotion importer.
|
||||
/// </summary>
|
||||
[InitializeOnLoadMethod]
|
||||
private static void RegisterMotionImporter()
|
||||
{
|
||||
CubismImporter.OnDidImportModel += OnModelImport;
|
||||
CubismImporter.OnDidImportMotion += OnFadeMotionImport;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cubism Import Event Handling
|
||||
|
||||
/// <summary>
|
||||
/// Create animator controller for MotionFade.
|
||||
/// </summary>
|
||||
/// <param name="importer">Event source.</param>
|
||||
/// <param name="model">Imported model.</param>
|
||||
private static void OnModelImport(CubismModel3JsonImporter importer, CubismModel model)
|
||||
{
|
||||
var dataPath = Directory.GetParent(Application.dataPath).FullName + "/";
|
||||
var assetPath = importer.AssetPath.Replace(".model3.json", ".controller");
|
||||
|
||||
var animator = model.GetComponent<Animator>();
|
||||
|
||||
if (!File.Exists(dataPath + assetPath))
|
||||
{
|
||||
var controller = CreateAnimatorController(assetPath);
|
||||
|
||||
if (!CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow)
|
||||
{
|
||||
if (animator != null)
|
||||
{
|
||||
animator.runtimeAnimatorController = controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (animator != null)
|
||||
{
|
||||
if (CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow)
|
||||
{
|
||||
animator.runtimeAnimatorController = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fadeController = model.GetComponent<CubismFadeController>();
|
||||
if (importer.Model3Json.FileReferences.Motions.Motions == null || fadeController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var modelDir = Path.GetDirectoryName(importer.AssetPath).Replace("\\", "/");
|
||||
var modelName = Path.GetFileName(modelDir);
|
||||
var fadeMotionListPath = modelDir + "/" + modelName + ".fadeMotionList.asset";
|
||||
|
||||
var fadeMotions = GetFadeMotionList(fadeMotionListPath);
|
||||
|
||||
if (fadeMotions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fadeController.CubismFadeMotionList = fadeMotions;
|
||||
|
||||
var fileReferences = importer.Model3Json.FileReferences;
|
||||
|
||||
// Create pose animation clip
|
||||
var motions = new List<CubismModel3Json.SerializableMotion>();
|
||||
|
||||
if (fileReferences.Motions.GroupNames != null)
|
||||
{
|
||||
for (var i = 0; i < fileReferences.Motions.GroupNames.Length; i++)
|
||||
{
|
||||
motions.AddRange(fileReferences.Motions.Motions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var shouldImportAsOriginalWorkflow = CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow;
|
||||
var shouldClearAnimationCurves = CubismUnityEditorMenu.ShouldClearAnimationCurves;
|
||||
|
||||
for (var i = 0; i < motions.Count; ++i)
|
||||
{
|
||||
var motionPath = Path.GetDirectoryName(assetPath) + "/" + motions[i].File;
|
||||
var jsonString = string.IsNullOrEmpty(motionPath)
|
||||
? null
|
||||
: File.ReadAllText(motionPath);
|
||||
|
||||
if (jsonString == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var directoryPath = Path.GetDirectoryName(assetPath) + "/";
|
||||
var motion3Json = CubismMotion3Json.LoadFrom(jsonString);
|
||||
|
||||
if (motion3Json == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var animationClipPath = directoryPath + motions[i].File.Replace(".motion3.json", ".anim");
|
||||
animationClipPath = animationClipPath.Replace("\\", "/");
|
||||
|
||||
var animationName = Path.GetFileNameWithoutExtension(motions[i].File.Replace(".motion3.json", ".anim"));
|
||||
var assetList = CubismCreatedAssetList.GetInstance();
|
||||
var assetListIndex = assetList.AssetPaths.Contains(animationClipPath)
|
||||
? assetList.AssetPaths.IndexOf(animationClipPath)
|
||||
: -1;
|
||||
|
||||
var animationClip = (shouldImportAsOriginalWorkflow)
|
||||
? (assetListIndex >= 0)
|
||||
? (AnimationClip)assetList.Assets[assetListIndex]
|
||||
: AssetDatabase.LoadAssetAtPath<AnimationClip>(animationClipPath)
|
||||
: null;
|
||||
|
||||
if (animationClip == null)
|
||||
{
|
||||
animationClip = motion3Json.ToAnimationClip(shouldImportAsOriginalWorkflow, shouldClearAnimationCurves, true);
|
||||
animationClip.name = animationName;
|
||||
}
|
||||
|
||||
var instanceId = 0;
|
||||
var isExistInstanceId = false;
|
||||
var events = animationClip.events;
|
||||
for (var k = 0; k < events.Length; ++k)
|
||||
{
|
||||
if (events[k].functionName != "InstanceId")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
instanceId = events[k].intParameter;
|
||||
isExistInstanceId = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isExistInstanceId)
|
||||
{
|
||||
// [Unity6.5] GetInstanceID() obsolete error 회피. EntityId→int 암시적 변환도 막혀
|
||||
// GetHashCode()를 쓴다 — 이 값은 아래 "InstanceId" 애니메이션 이벤트와
|
||||
// MotionInstanceIds 배열에 함께 구워지고 런타임은 구운 값끼리만 비교하므로 안전하다.
|
||||
instanceId = animationClip.GetEntityId().GetHashCode();
|
||||
}
|
||||
|
||||
var motionName = Path.GetFileName(motions[i].File);
|
||||
var motionIndex = -1;
|
||||
for (var fadeMotionIndex = 0; fadeMotionIndex < fadeMotions.CubismFadeMotionObjects.Length; fadeMotionIndex++)
|
||||
{
|
||||
if (Path.GetFileName(fadeMotions.CubismFadeMotionObjects[fadeMotionIndex].MotionName) != motionName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
motionIndex = fadeMotionIndex;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create fade motion.
|
||||
CreateFadeMotionData(motionIndex, instanceId, fadeMotions, motionPath, motion3Json, animationClip, importer.Model3Json);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create oldFadeMotion.
|
||||
/// </summary>
|
||||
/// <param name="importer">Event source.</param>
|
||||
/// <param name="animationClip">Imported motion.</param>
|
||||
private static void OnFadeMotionImport(CubismMotion3JsonImporter importer, AnimationClip animationClip)
|
||||
{
|
||||
// Add reference of motion for Fade to list.
|
||||
var directoryName = Path.GetDirectoryName(importer.AssetPath);
|
||||
var modelDir = Path.GetDirectoryName(directoryName);
|
||||
var modelName = Path.GetFileName(modelDir);
|
||||
var fadeMotionListPath = modelDir + "/" + modelName + ".fadeMotionList.asset";
|
||||
|
||||
var fadeMotions = GetFadeMotionList(fadeMotionListPath);
|
||||
|
||||
if (fadeMotions == null)
|
||||
{
|
||||
Debug.LogError("CubismFadeMotionImporter : Can not create CubismFadeMotionList.");
|
||||
return;
|
||||
}
|
||||
|
||||
var instanceId = 0;
|
||||
var isExistInstanceId = false;
|
||||
var events = animationClip.events;
|
||||
for (var k = 0; k < events.Length; ++k)
|
||||
{
|
||||
if (events[k].functionName != "InstanceId")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
instanceId = events[k].intParameter;
|
||||
isExistInstanceId = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isExistInstanceId)
|
||||
{
|
||||
// [Unity6.5] GetInstanceID() obsolete error 회피 (위 주석 참고)
|
||||
instanceId = animationClip.GetEntityId().GetHashCode();
|
||||
}
|
||||
|
||||
|
||||
var motionName = Path.GetFileName(importer.AssetPath);
|
||||
var motionIndex = -1;
|
||||
|
||||
for (var i = 0; i < fadeMotions.CubismFadeMotionObjects.Length; i++)
|
||||
{
|
||||
if (Path.GetFileName(fadeMotions.CubismFadeMotionObjects[i].MotionName) != motionName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
motionIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create fade motion.
|
||||
CreateFadeMotionData(motionIndex, instanceId, fadeMotions, importer.AssetPath, importer.Motion3Json, animationClip);
|
||||
|
||||
// Add animation event
|
||||
{
|
||||
var sourceAnimationEvents = AnimationUtility.GetAnimationEvents(animationClip);
|
||||
var index = -1;
|
||||
|
||||
for(var i = 0; i < sourceAnimationEvents.Length; ++i)
|
||||
{
|
||||
if(sourceAnimationEvents[i].functionName != "InstanceId")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(index == -1)
|
||||
{
|
||||
index = sourceAnimationEvents.Length;
|
||||
Array.Resize(ref sourceAnimationEvents, sourceAnimationEvents.Length + 1);
|
||||
sourceAnimationEvents[sourceAnimationEvents.Length - 1] = new AnimationEvent();
|
||||
}
|
||||
|
||||
sourceAnimationEvents[index].time = 0;
|
||||
sourceAnimationEvents[index].functionName = "InstanceId";
|
||||
sourceAnimationEvents[index].intParameter = instanceId;
|
||||
sourceAnimationEvents[index].messageOptions = SendMessageOptions.DontRequireReceiver;
|
||||
|
||||
AnimationUtility.SetAnimationEvents(animationClip, sourceAnimationEvents);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Functions
|
||||
|
||||
/// <summary>
|
||||
/// Create animator controller for MotionFade.
|
||||
/// </summary>
|
||||
/// <param name="assetPath"></param>
|
||||
/// <returns>Animator controller attached CubismFadeStateObserver.</returns>
|
||||
public static AnimatorController CreateAnimatorController(string assetPath)
|
||||
{
|
||||
var animatorController = AnimatorController.CreateAnimatorControllerAtPath(assetPath);
|
||||
animatorController.layers[0].stateMachine.AddStateMachineBehaviour<CubismFadeStateObserver>();
|
||||
|
||||
return animatorController;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the .fadeMotionList.
|
||||
/// If it does not exist, create a new one.
|
||||
/// </summary>
|
||||
/// <param name="fadeMotionListPath">The path of the .fadeMotionList.asset relative to the project.</param>
|
||||
/// <returns>.fadeMotionList.asset.</returns>
|
||||
private static CubismFadeMotionList GetFadeMotionList(string fadeMotionListPath)
|
||||
{
|
||||
var assetList = CubismCreatedAssetList.GetInstance();
|
||||
var assetListIndex = assetList.AssetPaths.Contains(fadeMotionListPath)
|
||||
? assetList.AssetPaths.IndexOf(fadeMotionListPath)
|
||||
: -1;
|
||||
|
||||
CubismFadeMotionList fadeMotions = null;
|
||||
|
||||
if (assetListIndex < 0)
|
||||
{
|
||||
fadeMotions = AssetDatabase.LoadAssetAtPath<CubismFadeMotionList>(fadeMotionListPath);
|
||||
|
||||
if (fadeMotions == null)
|
||||
{
|
||||
// Create reference list.
|
||||
fadeMotions = ScriptableObject.CreateInstance<CubismFadeMotionList>();
|
||||
fadeMotions.MotionInstanceIds = new int[0];
|
||||
fadeMotions.CubismFadeMotionObjects = new CubismFadeMotionData[0];
|
||||
AssetDatabase.CreateAsset(fadeMotions, fadeMotionListPath);
|
||||
}
|
||||
|
||||
assetList.Assets.Add(fadeMotions);
|
||||
assetList.AssetPaths.Add(fadeMotionListPath);
|
||||
assetList.IsImporterDirties.Add(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
fadeMotions = (CubismFadeMotionList)assetList.Assets[assetListIndex];
|
||||
}
|
||||
|
||||
return fadeMotions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of <see cref="CubismFadeMotionData"/> and save it as .fade.asset.
|
||||
/// </summary>
|
||||
/// <param name="motionIndex">The index in fadeMotions.CubismFadeMotionObjects.</param>
|
||||
/// <param name="instanceId">Motion's instance id.</param>
|
||||
/// <param name="fadeMotions">Target CubismFadeMotionList.</param>
|
||||
/// <param name="motion3JsonAssetsPath">Path of target.motion3.json</param>
|
||||
/// <param name="motion3Json">Target <see cref="CubismMotion3Json"/> instance.</param>
|
||||
/// <param name="animationClip">Imported motion.</param>
|
||||
/// <param name="model3Json"><see cref="CubismModel3Json"/> instance for get FadeInTime and FadeOutTime.</param>
|
||||
private static void CreateFadeMotionData(int motionIndex, int instanceId, CubismFadeMotionList fadeMotions, string motion3JsonAssetsPath, CubismMotion3Json motion3Json, AnimationClip animationClip, CubismModel3Json model3Json = null)
|
||||
{
|
||||
// Create fade motion.
|
||||
CubismFadeMotionData fadeMotion;
|
||||
if (motionIndex != -1)
|
||||
{
|
||||
var oldFadeMotion = fadeMotions.CubismFadeMotionObjects[motionIndex];
|
||||
|
||||
fadeMotion = CubismFadeMotionData.CreateInstance(
|
||||
oldFadeMotion,
|
||||
motion3Json,
|
||||
motion3JsonAssetsPath,
|
||||
animationClip.length,
|
||||
CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow,
|
||||
CubismUnityEditorMenu.ShouldClearAnimationCurves,
|
||||
model3Json);
|
||||
|
||||
EditorUtility.CopySerialized(fadeMotion, oldFadeMotion);
|
||||
|
||||
fadeMotions.MotionInstanceIds[motionIndex] = instanceId;
|
||||
fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create fade motion instance.
|
||||
fadeMotion = CubismFadeMotionData.CreateInstance(
|
||||
motion3Json,
|
||||
motion3JsonAssetsPath,
|
||||
animationClip.length,
|
||||
CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow,
|
||||
CubismUnityEditorMenu.ShouldClearAnimationCurves,
|
||||
model3Json);
|
||||
|
||||
AssetDatabase.CreateAsset(
|
||||
fadeMotion,
|
||||
motion3JsonAssetsPath.Replace(".motion3.json", ".fade.asset"));
|
||||
|
||||
motionIndex = fadeMotions.MotionInstanceIds.Length;
|
||||
|
||||
Array.Resize(ref fadeMotions.MotionInstanceIds, motionIndex + 1);
|
||||
fadeMotions.MotionInstanceIds[motionIndex] = instanceId;
|
||||
|
||||
Array.Resize(ref fadeMotions.CubismFadeMotionObjects, motionIndex + 1);
|
||||
fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion;
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(fadeMotion);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 103865783cfc2dd4eafa65a9def73dcd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"reference": "GUID:e5d337e0b3581c343aafde08e6e1727e"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40cb8dcf56e2a45479c9a740d8fd36ff
|
||||
AssemblyDefinitionReferenceImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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 System.Collections.Generic;
|
||||
|
||||
namespace Live2D.Cubism.Framework.MotionFade
|
||||
{
|
||||
/// <summary>
|
||||
/// Cubism fade state interface.
|
||||
/// </summary>
|
||||
public interface ICubismFadeState
|
||||
{
|
||||
/// <summary>
|
||||
/// Get cubism playing motion list.
|
||||
/// </summary>
|
||||
/// <returns>Cubism playing motion list.</returns>
|
||||
List<CubismFadePlayingMotion> GetPlayingMotions();
|
||||
|
||||
/// <summary>
|
||||
/// Is default state.
|
||||
/// </summary>
|
||||
/// <returns><see langword="true"/> State is default; <see langword="false"/> otherwise.</returns>
|
||||
bool IsDefaultState();
|
||||
|
||||
/// <summary>
|
||||
/// Get layer weight.
|
||||
/// </summary>
|
||||
/// <returns>Layer weight.</returns>
|
||||
float GetLayerWeight();
|
||||
|
||||
/// <summary>
|
||||
/// Get state transition finished.
|
||||
/// </summary>
|
||||
/// <returns><see langword="true"/> State transition is finished; <see langword="false"/> otherwise.</returns>
|
||||
bool GetStateTransitionFinished();
|
||||
|
||||
/// <summary>
|
||||
/// Set state transition finished.
|
||||
/// </summary>
|
||||
/// <param name="isFinished">State is finished.</param>
|
||||
void SetStateTransitionFinished(bool isFinished);
|
||||
|
||||
/// <summary>
|
||||
/// Stop animation.
|
||||
/// </summary>
|
||||
/// <param name="index">Playing motion index.</param>
|
||||
void StopAnimation(int index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3334b81e0ea7914c8f03981942eab17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user