MotionFade
最終更新: 2019年3月28日
概述
使用MotionFade重现与Unity上的Viewer for OW相同的动态渐变和参数渐变。
单击此处了解有关Cubism动态渐变和参数渐变的更多信息。
在Viewer for OW中,当切换动态时,每个动态都会在缓动时淡入/淡出。
但是在Unity中,当动画切换时,只是一个没有缓动的直线渐变,而这个功能用来表达和Viewer for OW一样的渐变。
MotionFade执行以下处理:
- 创建[.fade.asset]
- 创建[.fadeMotionList]并追加[.fade.asset]
- 保存AnimationClip instanceID
- 创建播放动态列表
- 渐变计算与应用
创建[.fade.asset]
[.fade.asset]是一个ScriptableObject资产,其中包含一条从[motion3.json]转换并用于渐变的混合曲线。
载入[motion3.json]时会与AnimationClip一起生成[.fade.asset]。
如果变更[.fade.asset],则无法保证正常运行。
要将[exp.json]转换为[.fade.asset],请执行以下处理:
- 解析[motion3.json]
- 创建CubismFadeMotionData
- 创建[.fade.asset]
解析[motion3.json]
要[motion3.json]的解析,使用CubismMotion3Json.LoadFrom(string motion3Json)或CubismMotion3Json.LoadFrom(TextAsset motion3JsonAsset)。
- string motion3Json[motion3.json]的字符串。
- TextAsset motion3JsonAsset[motion3.json]文本文件资产。
创建CubismFadeMotionData
CubismFadeMotionData是一个记录渐变信息的类,保存以下信息:
| 场地 | 型 | 说明 |
| MotionName | string | 动态名称。 |
| FadeInTime | float | 直到动态淡入的时间。值的单位是秒。 |
| FadeOutTime | float | 直到动态淡出的时间。值的单位是秒。 |
| ParameterIds | string[] | 动态使用的参数ID。 |
| ParameterCurves | AnimationCurve[] | 动态应用于参数的曲线。 |
| ParameterFadeInTimes | float[] | 由于参数渐变,参数淡入所需的时间。值的单位是秒。如果设置了负值,将应用FadeInTime。 |
| ParameterFadeOutTimes | float[] | 由于参数渐变,参数淡出所需的时间。值的单位是秒。如果设置了负值,将应用FadeOutTime。 |
| MotionLength | float | 该动态的长度。值的单位是秒。 |
使用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);
| 参数 | 型 | 说明 |
| fadeMotion | CubismFadeMotionData | 覆盖对象CubismFadeMotionData。 |
| motion3Json | CubismMotion3Json | 解析为.motion3.json的数据。 |
| motionName | string | 动态名称。 |
| motionLength | float | 动态的长度。值的单位是秒。 |
| shouldImportAsOriginalWorkflow | bool | 是否作为OriginalWorkflow载入。 |
| isCallFormModelJson | bool | 是从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必须在动画处理之后应用。