MotionFade
업데이트: 2019/03/28
개요
Unity에서 Viewer for OW와 동일한 모션 페이드, 파라미터 페이드를 재현하려면 MotionFade를 사용합니다.
Cubism의 모션 페이드, 파라미터 페이드에 대해 여기에서 자세히 알아보세요.
Viewer for OW에서는 모션이 전환될 때는 각각이 이징하면서 페이드 인/페이드 아웃합니다.
하지만 Unity에서는 애니메이션이 전환될 때는 이징하지 않고 선형으로 페이드만 되고 있어 Viewer for OW와 같은 페이드를 표현하기 위해서는 이 기능을 사용합니다.
MotionFade는 다음을 수행합니다.
- [.fade.asset] 만들기
- [.fadeMotionList]를 만들고 [.fade.asset] 추가
- AnimationClip의 instanceID 저장
- 재생 모션 목록 만들기
- 페이드 계산 및 적용
[.fade.asset] 만들기
[.fade.asset]은 [motion3.json]에서 변환하고 페이드에 사용할 블렌드용 커브를 포함하는 ScriptableObject의 애셋입니다.
[.fade.asset]은 [motion3.json]을 가져올 때 AnimationClip과 함께 생성됩니다.
[.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 | 그 모션의 길이. 값의 단위는 초. |
[.fade.asset]를 새로 만들고 덮어쓰기 저장하려면 CreateInstance를 사용합니다.
제1인수에 이미 생성된 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] 추가
[.fadeMotionList.asset]에 [.fade.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 저장용 이벤트 취득 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 저장용 이벤트가 없는 경우 이벤트 추가 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에 이벤트 설정 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의 적용은 애니메이션 처리 후에 실시해야 합니다.