MotionFade

업데이트: 2019/03/28

개요

Unity에서 Viewer for OW와 동일한 모션 페이드, 파라미터 페이드를 재현하려면 MotionFade를 사용합니다.

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]은 [motion3.json]에서 변환하고 페이드에 사용할 블렌드용 커브를 포함하는 ScriptableObject의 애셋입니다.
[.fade.asset]은 [motion3.json]을 가져올 때 AnimationClip과 함께 생성됩니다.
[.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그 모션의 길이. 값의 단위는 초.

[.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);
인수유형설명
fadeMotionCubismFadeMotionData덮어쓰기 대상인 CubismFadeMotionData.
motion3JsonCubismMotion3Json.motion3.json을 투시한 데이터.
motionNamestring모션의 이름.
motionLengthfloat모션의 길이. 값의 단위는 초.
shouldImportAsOriginalWorkflowboolOriginalWorkflow로 가져올지 여부.
isCallFormModelJsonboolmodel3.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의 적용은 애니메이션 처리 후에 실시해야 합니다.

이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.