MotionFade
最終更新: 2019年3月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を使用します。
第一引数に、既に生成された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<CubismFadePlayingMotion> 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の適用はアニメーション処理の後に行う必要があります。