gologiusの巣

プログラミングなどの技術メモです。誰かの役に立てるとうれしいです。

【Unity】 Playable APIで上半身と下半身を別々のモーションをさせる【改良版】

※2018/03/03追記:バージョンアップでモーションが動かなくなる不具合を修正(最後に説明)

やりたいこと

前回

前回の問題は

  • RigがHumanoidの場合、挙動がおかしい
  • AnimationLayerMixerPlayable の理解が微妙
  • (記事には書いてないけど) そもそもAvaterMaskは一つでいいのでは?
    • AnimatorControllerを使う場合、AvaterMaskは上半身分のみでよい
    • 実装をもうちょいきれいにできるのでは?

でした。解決していきましょう。

実装結果

実際に実装したものがこちら(左:Humanoid、 右がGeneric)

サンプルプロジェクトはこちら

GitHub - gologius/PlayabkeMask: Playable APIでマスクをするテスト

使用方法

1「上半身分」のAvaterMaskを作成する ※前回は下半身分も作成しましたが、いらないことが判明しました。 f:id:gologius:20171120233424p:plain

f:id:gologius:20171120233300p:plain

2 Animatorがアタッチされている場所にMotionPlayerをアタッチ f:id:gologius:20180104005628p:plain

3 先ほど作成したAvaterMaskをMotionPlayerにD&Dでセットする

4 MotionPlayer.play(AnimationClip clip, int layer, bool loop)を何らかの方法で呼ぶ

  • サンプル プロジェクトでは、MotionTest内から呼び出してます
  • AnimationClipもここで指定

解説

f:id:gologius:20180104012133p:plain

  • ※この理解であっているかは不明

  • AnimationMixerPlayableはモーション切り替え時に、変更前モーションと変更後モーションをいい感じでブレンドするためのミキサー。

  • SetLayerMaskFromAvatarMask(1, upperMask)で、LayerIndexとAvaterMask(上書きする部位)を指定している
    • ※ここでいうLayerIndexはAnimationLayerMixerPlayableInputIndexと(おそらく)同じ
    • InputIndexは、ConnectInput()で指定するもの
  • なので、SetLayerMaskFromAvatarMask()したレイヤ番号と同じInputIndexに、上半身用のモーションを流しこめば、 【A】ベースとなるモーション、の該当部分(サンプルの場合上半身)が、【B】のモーションに上書きされる

疑問

AnimationLayerMixerPlayableのWeight全く弄っていないのですが、いいんでしょうかね。。。

※【2018/03/03追記】...という疑問が2018/01時点ではあったんですが、アップデートで見事に修正されました。 恐らく、関数定義がUnity2017.1時点では

AnimationLayerPlayable(int inputIndex, ...... float weight = 1f)

となってたんでしょうが、Unity2017.3では

AnimationLayerPlayable(int inputIndex, ...... float weight = 0f)

になっており、明示的にweightを指定してあげないと、全くモーションが反映されない模様です。 サンプルも修正しました

【Unity】【エディタ拡張】 ObjectFieldを横に並べる

f:id:gologius:20171219225213p:plain もうすぐクリスマスなので、ObjectFieldをこんな感じで並べたくないですか?色とかつけて見やすくしたくないですか・・・?

簡単そうに見えて地味に面倒なこの作業を説明します。

なにが難しいのか

ObjectFieldの場合、ラベルが使用するマージン?を弄らないと、下のようになる。 f:id:gologius:20171219225406p:plain 隠れてしまって見えないですね。

なので、EditorGUIUtility.labelWidth = 100;でラベルが使用するマージン?を設定してあげます。

ソース

背景色を付けたり、太字にしたりする方法はソースみればわかると思います。 LayoutTest.cs · GitHub

【2017/12/23追記】値が入っている場合に色を変更する機能の追加と、バグ修正 f:id:gologius:20171223142413p:plain

  [System.Serializable]
    public class Content
    {
        public AnimationClip clip;
        public Transform trans;
    }

この部分、MonoBehaviourを継承してないので、’[System.Serializable]’を追加しないと、値を保存してくれない(実行すると値が消える)

参考

【Akeytsu】MirrorSelectedがIKで動かない

コメントいただいたので調べてみました。

症状

IKでMirrorSelected(左右対称にする)をするとバグる f:id:gologius:20171126093400p:plain f:id:gologius:20171126093505p:plain

IKの付け方 Akeytsu IKの使用方法メモ - gologiusの巣

モデルはお借りしました ImagineGirls – ImagineGirls オフィシャルサイト

原因

たぶん左右の対応がとれていない。Akeytsuではボーンの名前(L,R,Left,Right)でとっているみたい。 gologius.hatenadiary.com

けどIKはL,Rの文字に対応してない?嘘だろ・・・バグだろこれ・・・

解決策

名前を変えるだけ

f:id:gologius:20171126093705p:plain f:id:gologius:20171126093715p:plain f:id:gologius:20171126093724p:plain (※足は無視してください。ネタです。)

【Unity】Playableで上半身と下半身を別々に動かす

※改良しました(2018/1/4) gologius.hatenadiary.com

※以下古い情報

やりたいこと

走りながら、飛びながら、滑りながら銃を撃ちたい場合、

  • 上半身:銃を撃つモーション
  • 下半身:走るor飛ぶor滑るモーション

という風にしたい。

これをAnimationControllerでなく、Playableで実現したい。

サンプル

ここからDL

GitHub - gologius/PlayabkeMask: Playable APIでマスクをするテスト

実行結果動画

スクリプト使用方法

※別のプロジェクトで使用する場合の方法

1 上半身と下半身のAvaterMaskを作成

f:id:gologius:20171120233424p:plain f:id:gologius:20171120233300p:plain 上半身or下半身に該当するTransformにチェックを入れてね!!

2 AnimatorのあるGameObjectにMotionPlayerをアタッチ、設定

f:id:gologius:20171120140538p:plain Maskと再生するクリップを指定

3 スクリプトやボタンなどから関数を叩く

MotionPlayer.playFromID()を叩く

実装説明

サンプル内で関係しているのはMotionPlayer.cs。下の図のようなことをして実現しようとしています。 f:id:gologius:20171120141438p:plain (※図はあくまで参考です。認識があっているかも若干怪しいです)

upperLayerMixer.SetLayerMaskFromAvatarMask(0, upperBodyMask);
lowerLayerMixer.SetLayerMaskFromAvatarMask(0, lowerBodyMask);

引数が(レイヤ番号、AvaterMask)なんですけど、LayerMixerを二つ作って、レイヤ番号は0にするのがポイントですね。 ・・・これ本当にあってるのか・・・?

課題

はじめにも書いたけど、RigがHumanoidだと上半身が動かない。

allLayerMixer.ConnectInput(0, upperLayerMixer, 0);
allLayerMixer.ConnectInput(1, lowerLayerMixer, 0);

これを

allLayerMixer.ConnectInput(1, upperLayerMixer, 0);
allLayerMixer.ConnectInput(0, lowerLayerMixer, 0);

すると、今度は下半身が動かない。 つまり、input番号1が優先されている状態になっている。謎。

参考

【Unity】 RequiredComponentが4つ以上指定できない場合

書き方の問題です。

[RequireComponent(typeof(Rigidbody), typeof(CapsuleCollider), typeof(MyClass))]
public class Character : MonoBehaviour {
}

この書き方で四つ目を追加するとエラーになる

//エラーになる書き方
[RequireComponent(typeof(Rigidbody), typeof(CapsuleCollider), typeof(MyClass), typeof(MyComp2))]
public class Character : MonoBehaviour {
}

なので

[RequireComponent(typeof(MyComp1))]
[RequireComponent(typeof(MyComp2))]
[RequireComponent(typeof(MyComp3))]
[RequireComponent(typeof(MyComp4))]
public class Character : MonoBehaviour {
}

こう書けばよい。

参考

https://forum.unity.com/threads/why-is-requirecomponent-limited-to-3-components.167232/

ちなみに「Unity requirecomponent more than 4」でググったら出た。

【Unity エディタ拡張】 AnimatorControllerが持つState名のついたAnimationClipファイルを一括作成する

経緯

OverrideControllerを使いたいのですが、AnimationClip名を指定というクソ仕様でした。

なのでState名がついた空のAnimationClipを自動生成し、それをセットします

何がうれしいの?

OverrideControllerの仕様上、下図のOriginalの名前が、Clip名になります。 State名が変わったり、増えたりすると、いちいち設定しないといけません。 また、Clip名とState名が一意に対応している、という保証もありません。

f:id:gologius:20171104130412p:plain

というかなぜStateで指定させてくれないの・・・???

コード

gist31d0b33762a1b5d88b9b8bb9eedd6dc9

printCustomLabel()は、前の記事で作成したものですね。直接今回の処理とか関係ありません。

また、複数レイヤーには対応してません(//todo のところ)

使い方

  1. Assets/Editor内にCustomAnimatorWindow.csを作成(フォルダがなければ新しく作成する)。
  2. 上のコードをコピペ
  3. 下のようにWindow->CustomAnimatorWindowをクリック

f:id:gologius:20171104093618p:plain

以下のような画面が出るので、適当に設定してボタンをおせばいいです。

f:id:gologius:20171104125811p:plain

その他

結局、ウインドウ開いてボタンを押す作業は発生しますが、手作業でファイル名を設定したりするよりも、はるかに安全かつ楽だと思います。