※都度更新予定
モーションを補間させながら遷移させる場合、Playable APIには関数は用意されていません(Unity2017.3現在)。
よって、PlayableAPIを使用する場合、自分でコードを書かなければなりません。
まぁ今後関数が用意される可能性もありますが・・・
というわけで、PlayableAPIでモーション遷移させる場合に、
注意したほうがさそうな場合について記載します。
個人的にはモーション切り替えパターンは
- とにかく指定したモーションにスムーズに移行してほしいパターン(棒立ち→走り始める、など)
- 上半身が別のモーションによって上書きされるパターン(走る→走りながら撃つ、など)
- 指定したモーションの最初のフレームから最後のフレームまで再生してほしいパターン(武器をちゃんと振ってほしい場合など)
- 遷移前の時間を引き継いでほしいパターン(前方向に歩く→右方向に歩く場合など。)
この四つのパターンにに分けられると思っています。今回はこの四つのパターンを実装したサンプルプロジェクトを作成しました。
サンプルプロジェクト
というわけで作成したサンプルプロジェクトを置いておきます。
github.com
実体はMotionPlayerコンポーネントです。Unityちゃんにアタッチされてます。
UIからモーション再生方法をいろいろ弄れます。
ちなみに逆再生も可能。
次からモーションの切り替えパターンの説明となります。
とにかく指定したモーションにスムーズに移行してほしいパターン
切り替え時にPlayableへのinputWeightを変更しながら、モーション切り替えをします(サンプルプロジェクトのMotionMixer. crossFadeCoroutine()
が該当)
・・・という基本的な考え方をこちらの記事から学びました。
tsubakit1.hateblo.jp
上半身が別のモーションによって上書きされるパターン
例えば、
layerMixer.SetLayerMaskFromAvatarMask(layerIndex=1, upperMask);
のように、Layer1に上半身のマスクを割り当てた状態で
layerMixer.SetInputWeight(layer=1, weight=1f);
のようにweight=1f
にすれば上半身のモーションは上書きされますし、weight=0f
にすれば、layer=0に適用されているモーションが上半身にも適用されます。
ただ、このweight切り替えの際にいきなり値を変えると、モーションが補間されすに切り替わってしまいます。
なので
private IEnumerator crossFadeLayerWeight(int layer, float duration, bool enable)
{
float waitTime = Time.time + duration;
yield return new WaitWhile(() =>
{
float diff = waitTime - Time.time;
float rate = Mathf.Clamp01(diff / duration);
float weight = (enable) ? 1 - rate : rate;
layerMixer.SetInputWeight(layer, weight);
if (diff <= 0)
return false;
else
return true;
});
}
のようにして値を補間させながら切り替えましょう(詳しくはMotionPlayer.setLayerEnabled( )を参照)。
※サンプルプロジェクトの場合「上半身上書き」にチェックを入れ、遷移時間のスライダを0以上にすると、遷移が見れます。
指定したモーションの最初のフレームから最後のフレームまで再生してほしいパターン
※サンプルプロジェクトの場合「完全遷移まで待機」にチェックを入れる、に該当します。
例えば武器を
1. 振り上げて
2. 振り下ろす
という二つで一つのモーションに遷移したい場合、遷移前のモーションがミックスされてしまうと、
2.振り下ろす のモーションしか再生されてないようにみえる可能性があります。
ですので、遷移後のモーションの一フレーム目の姿勢になるまで、再生を待ってあげる必要があります。
またせる処理はコルーチンを使えば大して難しくないですね。以下のように遷移先のモーション再生を停止させておき、一定時間後にモーション再生を再開します(詳しくはMotionMixer. crossFadeCoroutine()
参照)
if (waitCrossFade)
nowPlayable.SetSpeed(0f); //遷移先のモーション時間を止めておく
//inputWeightの変更 略
if (waitCrossFade)
{
float play_speed = playParam.reverse ? -1f : 1f;
nowPlayable.SetSpeed(play_speed); //遷移先のモーション再生時間を元に戻す
}
遷移前の時間を引き継いでほしいパターン
※サンプルプロジェクトの場合「アニメーション時間同期」にチェックを入れる、に該当します。
例えば走るモーションが、正面、左、右の3パターンあり、すべて同じ周期で走っているとします。
この場合時間同期させながら遷移させないと、片足で移動しているように見えてしまいます。
なので、再生する時に、遷移前のモーションの再生中時間を
nowPlayable.SetTime(beforePlayable.GetTime());
のようにして引き継いであげる必要があります。
サンプルではMotionMixer.recconect()
内に処理があります。
まとめ
- Playable APIでモーション遷移する際のパターンについて書きました
- いかんせん動画か資料がないとわかりづらい内容なので、記事を書く準備が面倒でしたね・・・
- この記事は追記、更新しまくると思います