がとーしょこらの技術録(旧)

記録や技術的な記事を書いていきます

[VRChat] Avatars3.0で物を出し入れする (EmoteSwitchみたいなもの)

この記事は以下に移行しました。今後の更新は以下でおこなわれます

https://gatosyocora.net/posts/vrchat_avatars3_action_switch/

はじめに

これまでのアバター(Avatars2.0)では
Emote(エモート)機能でオブジェクトを出したり、消したりするギミック(通称:EmoteSwitch)がありました。

Avatars 3.0ではアクションメニューを拡張してボタンを追加することで、
そのボタンの操作によってオブジェクトを出したり、消したりできるようになりました。

これはEmoteSwitch(エモートスイッチ)に比べて、

  • 単純な設計で実装できる
  • 後からインスタンスに来た人にもオブジェクトの状態が同期する
  • 多くのオブジェクトの出し入れを管理できる
  • ワールドを移動してもオブジェクトの状態が維持されるようにできる

などメリットがいくつもあります。

この記事ではAvatars3.0のアクションメニューのToggleボタン操作によって、
後から来た人にも同期するようにオブジェクトを出し入れするギミック(以下、ActionSwitch)を実装する方法を解説します。

[2020/8/31]
2つ以上の物を入れ替えるときに一瞬同時に出てしまう問題を解消する方法を追記しました。

[2021/1/10]
WriteDefaultsの注意について追記しました。

[2021/3/26]
ギミックに使用するParameterの種類をIntからBoolに変更しました。
WriteDefaultsがオフを想定した内容に変更しました。

動作確認環境

  • Unity 2018.4.20f1
  • VRCSDK3-AVATAR-2021.03.22.18.27_Public.unitypackage

実装する手順

この記事では実装手順の紹介なのでCubeを使ってオブジェクトの出し入れを紹介します。
他のもの(服や武器など)の出し入れの場合は本記事のCubeの部分を置き換えて実装してみてください。

【注意】(2021/1/10, 3/26追記)
以下は各StateのWriteDefaultsがオフ(チェックが入っていない)を想定しています。
オンとオフが混在している場合、ギミックがうまく動作しないことがあるので注意してください。

f:id:gatosyocora:20210110193645p:plain

大まかな手順

  1. FXに設定されたAnimatorControllerに新しいLayerを追加する
    (これに対してStateを追加したりしていく)
    • weightが1になっているか確認
  2. 初めから存在するEntry, AnyState, Endに加えて、新しく以下のStateを追加する
    • CubeOFF : Cubeが出ていない状態(デフォルト状態)
    • CubeON : Cubeが出ている状態(アクティブ状態)
  3. 各StateのWriteDefaultsをオフ(チェックが入っていない状態)にする
  4. Entry->CubeOFF->CubeON->Endとなるように遷移の矢印を追加する
  5. AnimationParameterにBool型の「ActiveCube」というパラメータを追加する(初期値false)
  6. 遷移の矢印に以下の設定をする
    • CubeOFF -> CubeON
      • Conditions : ActiveCube true
      • Has Exit Time : false
      • Transition Duration(s) : 0 [2020/8/31追記]
    • CubeON -> End
      • Conditions : ActiveCube false
      • Has Exit Time : false
      • Transition Duration(s) : 0 [2020/8/31追記]
  7. CubeONに以下のようなAnimationClipを設定する
    • CubeのActiveをtrue (表示) にする
    • 0フレーム目にのみキーを持つ
  8. CubeOFFに以下のようなAnimationClipを設定する
    • CubeのActiveをfalse (表示) にする
    • 0フレーム目にのみキーを持つ
  9. CubeのデフォルトのActiveはfalse (非表示) にしておく
  10. Expression ParametersにBool型の「ActiveCube」というパラメータを追加する
  11. Expressions Menuに以下のようなControlを追加する
    • Type : Toggle
    • Parameter : ActiveCube

1. ActionSwitchの実装の準備

VRCAvatarDescriptorのPlayable LayersのFXに設定されたAnimatorControllerをダブルクリックして選択します。
(まだ設定されていない場合、Assets/VRCSDK/Examples3/Animation/Controllersにあるvrc_AvatarV3HandsLayerを複製してここに設定してください。)

次に、選択された状態でAnimatorウィンドウを開きます。
(Unity上部のWindow>Animation>Animatorで開けます。) f:id:gatosyocora:20200807161328p:plain

左上にある「+」を押して新しいLayerを作成します。
Layerには分かりやすい名前をつけてください。
今回はCubeを出すのでCubeという名前をつけました。
Debugメニューで文字化けしてしまうため、日本語ではなく英語の名前にしたほうがよいです。

f:id:gatosyocora:20200807224551p:plain

次に右のほうにある歯車のマークをクリックして、
以下の画像のようなLayerの設定画面を開きます。

f:id:gatosyocora:20200807225633p:plain

Weightの項目を0から1に変更してください。
このようにLayerのWeightを1にしないと、
そのLayerでの変更はアバターに反映されないので注意が必要です。(よく忘れがち)

f:id:gatosyocora:20200807225651p:plain

これで新しいギミックを作成する準備は完了です。
この流れは今回紹介するActionSwitchだけでなく、
多くのギミックを新しく実装する手順に含まれる操作です。

2. ActionSwitchの実装

今回はActionSwitchを使って、
Cubeを出したり、消したりしていきます。
以下の画像が完成したときのStateとParameterです。
これを目指して作っていきます。
f:id:gatosyocora:20210326002316p:plain

2.1 Stateの作成と設定

このギミックはCubeが出ている状態と出ていない状態の2つの状態でできています。
先ほどの画像では

  • 橙色のStateがCubeが出ていない状態(デフォルト状態)
  • 灰色のStateがCubeが出ている状態(アクティブ状態)

のようになっています。

まず、まだCubeを出していないデフォルト状態を作成します。
何もない場所で右クリックして、
Create State>Emptyで新しいStateを作成します。

f:id:gatosyocora:20200807225857p:plain

f:id:gatosyocora:20200807225913p:plain

同じ手順でCubeが出ているアクティブ状態のStateも作成します。

f:id:gatosyocora:20200807225937p:plain

それぞれのStateをクリックするとInspectorに詳細が表示されます。

f:id:gatosyocora:20200807230236p:plain

ここの名前部分を選択して、それぞれのStateを分かりやすい名前にしておきましょう。
Debugメニューで文字化けしてしまうため、日本語ではなく英語の名前にしたほうがよいです。

CubeOFF : Cubeが出ていない状態(デフォルト状態)橙色
CubeON:Cubeが出ている状態(アクティブ状態)灰色

f:id:gatosyocora:20200808110742p:plain

また、VRChat公式ではWriteDefaultsはオフを推奨しているのでこちらもチェックを外しておきましょう

f:id:gatosyocora:20210326010627p:plain

次にState同士を矢印でつないでいきます。
CubeOFFのStateを右クリックして、Make Transitionを選択します。

f:id:gatosyocora:20200808111633p:plain

すると矢印がついた白線がマウスに追従するのでその状態でCubeONのStateをクリックします。
これでCubeOFFからCubeONへの矢印(遷移, Transition)が追加されました。

f:id:gatosyocora:20200808111912p:plain

同じように今度はCubeONからExit(赤色のState)に向けて矢印を追加します。

f:id:gatosyocora:20200808111958p:plain

2.2 Parameterの作成と設定

次にStateから別のStateへの移動の条件を設定するためにParameterを設定します。

Layersの横にあるParametersをクリックして、
そのAnimatorControllerに設定されたAnimationParameterの一覧を表示します。

f:id:gatosyocora:20200808113502p:plain

左上にある「+」をクリックして新しいParameterを追加します。
今回はオブジェクトを出し入れするのでBoolを選択します。

f:id:gatosyocora:20210326002543p:plain

名前はActiveCubeにしました。
特にこれでないといけないわけではないですが、
以降でActiveCubeを選択・設定するときに同じ名称になるようにしてください。
また、日本語ではなく英語の名前にしたほうがよいです。

f:id:gatosyocora:20210326002712p:plain

次にLayersを押してLayer一覧に戻り、記事序盤で作成した「Cube」レイヤーを選択します。

f:id:gatosyocora:20200808113803p:plain

f:id:gatosyocora:20200808113911p:plain

CubeOFFとCubeONの間にある矢印をクリックします。
するとInspectorに矢印の詳細が表示されます。

f:id:gatosyocora:20200808123332p:plain

f:id:gatosyocora:20200808123349p:plain

Conditionsの「+」をクリックして新しい項目を追加します。
f:id:gatosyocora:20200808123439p:plain

左から順にActiveCube, trueに変更します。
これでCubeOFFにいるときにActiveCubeというParameterがtrue(チェックが入った状態)になったらCubeONに移動します。

f:id:gatosyocora:20210326002859p:plain

さらにHas Exit Timeのチェックを外します。

f:id:gatosyocora:20200808124115p:plain

[2020/8/31追記]
また、SettingsにあるTransition Duration (s) を0にします。
これはStateの遷移にかける時間で、0より大きい場合、State間の状態が補完されながら遷移されます。

f:id:gatosyocora:20200831155438p:plain

これでCubeが出ていないデフォルト状態からCubeが出ているアクティブ状態にするギミック部分はできました。

次にCubeが出ているアクティブ状態からCubeが出ていないデフォルト状態に戻す部分を作っていきます。

CubeONのStateとExitのStateの間にある矢印を選択します。
f:id:gatosyocora:20200808125231p:plain

先ほどと同じような手順でConditionsとTransition Duration, Has Exit Timeを以下のように設定します。

Has Exit Time : チェックを外す
Transition Duration (s) : 0
Conditions : ActiveCube false

f:id:gatosyocora:20210326003250p:plain

2.3 Animationの作成と設定

アバターにCubeを追加します
(説明用にCubeを追加しているので、
このCubeが今回出し入れしたいものだと考えてもらって大丈夫です)

Cubeの代わりにするオブジェクトにAnimatorがついている場合には削除してください。

f:id:gatosyocora:20200808133831p:plain f:id:gatosyocora:20200808133850p:plain

2.3.1 表示状態にするAnimation(CubeOn)の作成

まず、Projectウィンドウで右クリックをして、
Create>AnimationでAnimationClipを作成します。
Cubeを出すアニメーションなのでCubeOnという名前にしました。

f:id:gatosyocora:20200808142950p:plain f:id:gatosyocora:20200808143014p:plain

次に先ほど触っていたAnimatorControllerに戻って、 CubeONのStateを選択します。
f:id:gatosyocora:20200808143213p:plain

CubeONのmotionに先ほど作成したCubeOnというAnimationClipを設定します。

f:id:gatosyocora:20200808143307p:plain

Animationの設定のために一時的に
アバターのルートにあるAnimatorのController
FXに設定されているAnimatorControllerを設定します。

f:id:gatosyocora:20200808145041p:plain

VRCAvatarDescriptorが設定されたオブジェクトを選択している状態で
Animationウィンドウを開きます。

f:id:gatosyocora:20200808145526p:plain

AnimationウィンドウはUnity上部のWindow>Animation>Animationで開けます。

f:id:gatosyocora:20200807162509p:plain

左側にあるPreviewの下をクリックすると、
先ほどAnimatorに設定したAnimatorControllerが持つAnimationClipの一覧が表示されます。
先ほど設定したCubeOnを選択してください。

f:id:gatosyocora:20200808145807p:plain

Previewの横の録画ボタンをクリックすると、録画モードが開始されます。

f:id:gatosyocora:20200808145946p:plain

この状態で出現させたいオブジェクト(本記事ではCube)を選択します。

f:id:gatosyocora:20200808150023p:plain

そしてInspectorの左上にあるチェックマークを入っている状態にします。
最初から入っている場合はチェックボックスを一度押して再度押して入っている状態にしてください。
下の画像のようになれば大丈夫です。

f:id:gatosyocora:20200808150210p:plain

すると先ほどのAnimationウィンドウにCubeのIs Activeを操作するキーが0:00のところに追加されました。 これがチェックマークが入っている状態になっていることを確認してください。

f:id:gatosyocora:20200808150331p:plain

これで録画は完了なので、Previewボタンを一度押して録画モードを停止してください。

f:id:gatosyocora:20200808150426p:plain

これでAnimationの準備は完了なので、AnimatorからAnimatorControllerを外しておきましょう。
Controllerの右の方にある二重丸を選択して一番上にあるNoneを選択すると外すことができます。

f:id:gatosyocora:20200808150641p:plain f:id:gatosyocora:20200808150731p:plain

Cubeは最初は消えている状態にするのでチェックを外して消しておきましょう。

f:id:gatosyocora:20200808150513p:plain

2.3.2 非表示状態にするAnimation(CubeOff)の作成

次にCubeを初期状態の非表示状態にするAnimationを作成します。
先ほど作成したCubeOn.animを選択した状態でCtrl+Dを押すと複製されます。

f:id:gatosyocora:20210326012213p:plain

複製されたCubeOn 1を右クリックしてRenameCubeOffという名前に変更します。

f:id:gatosyocora:20210326012347p:plain

Animatorウィンドウを開いて、CubeOFFステートのMotionに複製したCubeOffを設定します。

f:id:gatosyocora:20210326012552p:plain

CubeOff.animを選択した状態でAnimationウィンドウを開くとその内容が見れます。

f:id:gatosyocora:20210326012724p:plain

Cube : Game Object.Is Active 1のようになっているので、1のところをクリックし、0に変更します。
これでCubeを非表示状態にするAnimationファイルになりました。

f:id:gatosyocora:20210326012817p:plain f:id:gatosyocora:20210326012833p:plain

これでギミック部分は完成しました。

2.4 ExMenuの設定

最後にメニュー操作でオブジェクトを出し入れできるようにします。

VRCAvatarDescriptorのExpressionsのParametersに設定しているExpressionParametersをダブルクリックして選択します。

f:id:gatosyocora:20200808151143p:plain

設定されていない場合はCreate>VRChat>Avatars>Expression Parametersで新しく作成して設定してください。

f:id:gatosyocora:20200808151429p:plain

左上のAddを押すと新しい項目が増えるのでNameにActiveCubeと入力してTypeはBoolを選択してください。
ここの名称はAnimatorControllerのParametersで新しく設定した名称と同じにしてください。
(大文字小文字も同じになるように)

DefaultはCubeが最初出ていない状態なのでチェックがない状態にします。
Savedは別のワールドやVRChatの再起動でもCubeが出ている状態を維持するためにチェックがある状態にします。(ここはお好みでどちらでも良いです)

f:id:gatosyocora:20210326003940p:plain f:id:gatosyocora:20210326002712p:plain

次にVRCAvatarDescriptorのExpressionsのMenuに設定しているExpressionsMenuをダブルクリックして選択します。

f:id:gatosyocora:20200808151711p:plain

設定されていない場合はCreate>VRChat>Avatars>Expressions Menuで新しく作成して設定してください。

f:id:gatosyocora:20200808151749p:plain

Add Controlを押して新しい項目を増やします。
既に項目が8個ある場合は追加できないので、
ExpressionMenuを新しくしてSubMenuとして追加することを検討してください。

f:id:gatosyocora:20200808151840p:plain

NameとIconは分かりやすいように設定してください。
TypeはToggle, ParameterはActiveCube, Boolに設定してください。

f:id:gatosyocora:20210326004554p:plain

これですべての設定が完了です。
VRChatにアップロードしてCubeを出してみましょう。

f:id:gatosyocora:20200808160215g:plain

3. 注意点(おさらい)

  • 新しく作成したLayerはweightが0になっているので1にする
  • オブジェクトの出し入れのギミックはFX Layerに設定したAnimatorControllerに追加する
  • Expression ParametersとAnimatorControllerのParameterの名称は完全に同じにする
  • AnimatorControllerにあるStateのWriteDefaultsはオフ(チェックが入っていない状態)にする

4.応用編

デフォルトで表示されているものを消す

本記事で紹介したものは「消えているものを表示する」でしたが、
その逆も紹介した方法の応用で実現できます。
おおまかな設定手順は同じで以下のものを変更します。

  • 出し入れするオブジェクトの左上のチェックを入れて表示されている状態にしておく(工程)
  • 設定するAnimationClipでIs Activeにチェックをはずす(工程)
  • 1を0に変更ではなく、0になっているので1に変更する(工程)

初期状態と変更後にどういう状態にするかを変えただけです。
これで「表示されているものを消す」というギミックになります。

さいごに

今回紹介した方法は個人的に最小構成でActionSwitchを実装する方法だと思います。
Expression Parametersの節約や初期状態でオブジェクトが出ているようにする方法など、応用する方法がいろいろあります。

また、これだけ長い手順なので毎回設定するのは大変です。
同じようなことを実現する方法としてこのようなツールも出ているので使ってみてもいいかもしれないです。
いろんな方が作っておられるので用途と自分にあったツールを選ぶのが良いと思います。

booth.pm

github.com