MotionFade

最終更新: 2019年3月28日

概述

使用MotionFade重现与Unity上的Viewer for OW相同的动态渐变和参数渐变。

单击此处了解有关Cubism动态渐变和参数渐变的更多信息。

在Viewer for OW中,当切换动态时,每个动态都会在缓动时淡入/淡出。
但是在Unity中,当动画切换时,只是一个没有缓动的直线渐变,而这个功能用来表达和Viewer for OW一样的渐变。

MotionFade执行以下处理:

  1. 创建[.fade.asset]
  2. 创建[.fadeMotionList]并追加[.fade.asset]
  3. 保存AnimationClip instanceID
  4. 创建播放动态列表
  5. 渐变计算与应用

创建[.fade.asset]

[.fade.asset]是一个ScriptableObject资产,其中包含一条从[motion3.json]转换并用于渐变的混合曲线。
载入[motion3.json]时会与AnimationClip一起生成[.fade.asset]。
如果变更[.fade.asset],则无法保证正常运行。

要将[exp.json]转换为[.fade.asset],请执行以下处理:

  1. 解析[motion3.json]
  2. 创建CubismFadeMotionData
  3. 创建[.fade.asset]

解析[motion3.json]

要[motion3.json]的解析,使用CubismMotion3Json.LoadFrom(string motion3Json)或CubismMotion3Json.LoadFrom(TextAsset motion3JsonAsset)。

  • string motion3Json[motion3.json]的字符串。
  • TextAsset motion3JsonAsset[motion3.json]文本文件资产。

创建CubismFadeMotionData

CubismFadeMotionData是一个记录渐变信息的类,保存以下信息:

场地说明
MotionNamestring动态名称。
FadeInTimefloat直到动态淡入的时间。值的单位是秒。
FadeOutTimefloat直到动态淡出的时间。值的单位是秒。
ParameterIdsstring[]动态使用的参数ID。
ParameterCurvesAnimationCurve[]动态应用于参数的曲线。
ParameterFadeInTimesfloat[]由于参数渐变,参数淡入所需的时间。值的单位是秒。如果设置了负值,将应用FadeInTime。
ParameterFadeOutTimesfloat[]由于参数渐变,参数淡出所需的时间。值的单位是秒。如果设置了负值,将应用FadeOutTime。
MotionLengthfloat该动态的长度。值的单位是秒。

使用CreateInstance创建一个新的[.fade.asset]并通过覆盖保存它。
如果您传递已生成的CubismFadeMotionData副本作为第一参数,则该副本将被覆盖和处理。

CubismFadeMotionData.CreateInstance(CubismMotion3Json motion3Json, string motionName, float motionLength, bool shouldImportAsOriginalWorkflow = false, bool isCallFormModelJson = false);
CubismFadeMotionData.CreateInstance(CubismFadeMotionData fadeMotion, CubismMotion3Json motion3Json, string motionName, float motionLength, bool shouldImportAsOriginalWorkflow = false, bool isCallFormModelJson = false);
参数说明
fadeMotionCubismFadeMotionData覆盖对象CubismFadeMotionData。
motion3JsonCubismMotion3Json解析为.motion3.json的数据。
motionNamestring动态名称。
motionLengthfloat动态的长度。值的单位是秒。
shouldImportAsOriginalWorkflowbool是否作为OriginalWorkflow载入。
isCallFormModelJsonbool是从model3.json的载入处理中调用的吗?

创建[.fade.asset]

[.fade.asset]是使用AssetDatabase.CreateAsset()创建的。

// 创建时
fadeMotion = CubismFadeMotionData.CreateInstance(
    importer.Motion3Json,
    importer.AssetPath.Replace(directoryPath, ""),
    animationClip.length,
    CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow,
    CubismUnityEditorMenu.ShouldClearAnimationCurves);

AssetDatabase.CreateAsset(fadeMotion, importer.AssetPath.Replace(".motion3.json", ".fade.asset"));

// 更新已创建的资产时
fadeMotion = CubismFadeMotionData.CreateInstance(
    oldFadeMotion,
    importer.Motion3Json,
    importer.AssetPath.Replace(directoryPath, ""),
    animationClip.length,
    CubismUnityEditorMenu.ShouldImportAsOriginalWorkflow,
    CubismUnityEditorMenu.ShouldClearAnimationCurves);

EditorUtility.CopySerialized(fadeMotion, oldFadeMotion);

// 更新Unity数据库
EditorUtility.SetDirty(fadeMotion);

该处理通过CubismFadeMotionImporter.OnFadeMotionImport()进行。

创建[.fadeMotionList]并追加[.fade.asset]

[.fadeMotionList.asset] 是一个资产,它包含一组与[.fade.asset]配对的AnimationClip副本ID。
[.fade.asset]列表的顺序是按照[motion3.json]的载入顺序追加的。
如果变更[.fadeMotionList.asset],则无法保证正常运行。

创建[.fadeMotionList]

在与模型预制相同的层次结构中创建[.fadeMotionList.asset]。

// 创建fadeMotionList
fadeMotions = ScriptableObject.CreateInstance<CubismFadeMotionList>();
fadeMotions.MotionInstanceIds = new int[0];
fadeMotions.CubismFadeMotionObjects = new CubismFadeMotionData[0]; AssetDatabase.CreateAsset(fadeMotions, fadeMotionListPath);

该处理通过CubismFadeMotionImporter.OnFadeMotionImport()进行。

追加[.fade.asset]

要将[.fade.asset]追加到[.fadeMotionList.asset],进行以下操作:

// 更新现有数据时
fadeMotions.CubismFadeMotionObjects[motionIndex] = fadeMotion;

// 追加新数据时
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; 

// 更新Unity数据库 
EditorUtility.SetDirty(fadeMotions);

该处理通过CubismFadeMotionImporter.OnFadeMotionImport()进行。

保存AnimationClip instanceID

AnimationClip的副本ID在该AnimationClip中保存为AnimationEvent。
* 由于AnimationClip.GetInstanceID()获得的副本ID可能因执行环境不同而在Unity和运行时间不同,因此可能无法确定AnimationClip。

// 获取保存副本ID的Event
var sourceAnimEvents = AnimationUtility.GetAnimationEvents(animationClip);
AnimationEvent instanceIdEvent= null;
for(var i = 0; i < sourceAnimEvents.Length; ++i)
{
    if(sourceAnimEvents[i].functionName != "InstanceId")
    {
        continue;
    }

    instanceIdEvent= sourceAnimEvents[i];
    break;
}

// 如果没有保存副本ID的Event,则追加Event
if(instanceIdEvent== null)
{
    instanceIdEvent= new AnimationEvent();
    Array.Resize(ref sourceAnimEvents, sourceAnimEvents.Length + 1);
    sourceAnimEvents[sourceAnimEvents.Length - 1] = instanceIdEvent;
}

// 设置副本ID 
instanceIdEvent.time = 0;
instanceIdEvent.functionName = "InstanceId";
instanceIdEvent.intParameter = instanceId;
instanceIdEvent.messageOptions = SendMessageOptions.DontRequireReceiver;

// 在AnimationClip中设置Event 
AnimationUtility.SetAnimationEvents(animationClip, sourceAnimEvents);

该处理通过CubismFadeMotionImporter.OnFadeMotionImport()进行。

创建播放动态列表

播放动态列表是计算渐变时参考的列表,它还保存有关使用CubismFadePlayingMotion播放的动态信息。

关于CubismFadePlayingMotion

CubismFadePlayingMotion是一个具有以下动态播放信息和渐变信息的类。

  • StartTime:动态播放开始时间。值的单位是秒。
  • EndTime:动态的退出时间。值的单位是秒。
  • FadeInStartTime:动态淡入开始时间。值的单位是秒。
  • Speed:动态播放速度。速度范围为0或更大。1与Cubism Editor中设置的速度相同。
  • Motion:包含动态渐变信息的CubismFadeMotionData。

关于ICubismFadeState

ICubismFadeState是一个用于获取渐变计算所需信息的接口。

ICubismFadeState的API:

  • List GetPlayingMotions()
    • 获取播放动态列表。
  • bool IsDefaultState()
    • 是否为默认状态。
  • float GetLayerWeight()
    • 获取层的权重。
  • bool GetStateTransitionFinished()
    • 过渡是否退出。
  • void SetStateTransitionFinished(bool isFinished)
    • 设置过渡的退出。
  • void StopAnimation(int index)
    • 停止播放由索引指定的动画。

关于CubismFadeStateObserver

CubismFadeStateObserver是一个继承ICubismFadeState,监控Animator的状态,创建播放动态列表的类。

播放动态列表使用在播放动画时调用的OnStateEnter()进行创建。

// 获取播放的AnimationClips
var animatorClipInfo = controller.GetNextAnimatorClipInfo(layerIndex);

// 设置正在播放的动画的退出时间
for (var i = 0; i < _playingMotions.Count; ++i)
{
    var motion = _playingMotions[i];

    if (motion.Motion == null)
    {
        continue;
    }

    var newEndTime = Time.time + motion.Motion.FadeOutTime;

    if (motion.EndTime < 0.0f || newEndTime < motion.EndTime)
    {
        motion.EndTime = newEndTime;
    }
}

// 创建和追加播放动画 
for (var i = 0; i < animatorClipInfo.Length; ++i)
{
    CubismFadePlayingMotion playingMotion;

    /*省略*/

    playingMotion.Motion = (motionIndex == -1)
        ? null
        : _cubismFadeMotionList.CubismFadeMotionObjects[motionIndex];

    playingMotion.Speed = 1.0f;
    playingMotion.StartTime = Time.time;
    playingMotion.FadeInStartTime = Time.time;
    playingMotion.EndTime = (playingMotion.Motion.MotionLength <= 0)
        ? -1
        : playingMotion.StartTime + playingMotion.Motion.MotionLength + playingMotion.Motion.FadeOutTime;

    _playingMotions.Add(playingMotion);
}

该处理通过CubismFadeMotionImporter.OnFadeMotionImport()进行。

渐变计算与应用

渐变的计算和应用使用CubismFadeController.UpdateFade()进行。

MotionFade必须在动画处理之后应用。

请问这篇文章对您有帮助吗?
关于本报道,敬请提出您的意见及要求。