見出し画像

【VRChat】VRC Avatar Parameter Driverでランダムにアイテムを出し入れする【同期対応】

挨拶


こんにちは、₺ƾ₺ƾkesera2です。
今回はVRC Avatar Parameter Driverを使って、防犯ブザーの音をランダムに出し入れしていきたいと思います。

対象の読者としては、FXレイヤーとかで表情触ったことがある人で、ランダムの処理とか同期の処理に興味がある方を対象にしています。それ以外の方でも分かりやすいように画像を多めにして解説していきたいと思います。

けせらが普段どんな感じで改変をしてるのかといったこともわかるようになっているので、よかったら最後までお付き合いください。
本題の同期可能なランダムパラメータを持つのAnimatorについてはかなり後ろの方にあるので飛ばしていただいても大丈夫です。
※その場合、アニメーターの作成(成功パターン)まで飛ばしてください。

どうぞ対戦よろしくお願いします。それでは、やっていきましょう。

お借りしたアセット

「いりこめのおどうぐばこ」様の「こどもランドセル」をお借りしました。素敵なランドセルを公開してくださり、ありがとうございます。

また、Unity上での動作確認に「Lyuma」様の「Av3Emulator」をお借りしました。Gesture Managerだと再生時にPhysboneのStretchの動作がAnimator上で確認ができなかったので、こちらをお借りしました。

やりたいこと


ランドセルに付属の防犯ブザーを引っ張ると音がなるようにしたい
  1. ブザーを引っ張ると、音がなる。

  2. 通常時のブザーの音とネタの音を切り替えれるようにする。

  3. ネタの音を再生するときはランダムで変えられるようにする。

完成のイメージ動画

作り方

以降の説明とunitypackage配布のために小悪魔なおもちちゃんはダミーのアバターにしておきました。ヒエラルキーのAvator RootにVRC Avator Descriptorが設定されています。アバターが存在しなくてもVRC Avatar Descriptorの設定があれば動作は確認できるので、簡略化いたしました。

サイズ調整・位置合わせをする

ランドセルのインポートが終わったら、Ransel_FとBuzzer_for_Ransel_Fを親子関係になるようにヒエラルキーに追加して、アバターへの位置合わせとサイズ調整を行ってください。

Dynamic BoneをPhysboneに変換する

buzzer1がDynamic BoneになっているのでPhysboneに変換したいと思います。

ヒエラルキー画面からVRC Avatar Descriptorのあるアバターのルートオブジェクトを選択して、VRChat SDK > Utilities > Convert DynamicBones To Physboneを選択するとDynamicBoneがPhysboneに変換されます。

Convert DynamicBones To Physbonesを選択
Proceedを選択
Dynamic BoneがPhysboneに変換される

Radiusの設定

ブザーを引っ張るための判定をつけていきます。buzzer1を選択した状態でPhysboneのCollision > Radiusの値をお好みの太さに調整してください。今回は0.02としました。

Max Stretchの設定

紐を引っ張れるようにするためにMax Streachの値を設定していきたいと思います。buzzer1のPhysboneのGrab & Pose > Max Stretchの値を1にします。こうすることでブザーを引っ張ったときにびよーんと伸びるようになります。

Physboneのパラメータの設定

ブザーが引っ張ったときのパラメータを使いたいのでbuzzer1を選択して、InspectorウィンドウのPhysboneのOptions > Parameterに「buzzer」と入力します。こうすることでもしブザーのPhysboneが持たれたときや引っ張られたときに「buzzer_IsGrabbed」や「buzzer_Streatch」といったパラメータでアニメータをコントロールできるようになります。

効果音の追加

音源を用意します。今回は「On-Jin ~音人~」様の音源をお借りしました。

※利用規約の引用

個人・サークル・学校関係・ボランティアでの利用に当てはまる場合は、様々な組込み利用事例(「配信」「活動」「販売」「出展」「出品」「その他活用」等、営利・非営利に関わらず)においてフリーでご利用いただけます。

ランダム再生用の音源については各自お好きなのを用意してください。
用意ができたら音源をUnityにインポートしておいてください。

Buzzer_for_ransel_Fを右クリック > Create Emptyを押してAudio Sourceコンポーネントで効果音を再生するためのGame Objectを追加していきます。今回は通常のブザー音に加えて、ランダムに再生するサウンド用のGame Objectを3つ追加しました。

※音源ファイルを直接ヒエラルキーにドラッグアンドドロップして追加してもOKです
その場合、次の手順は省略できます。
こちらの手順では、命名の統一のためにワンステップ踏んでいます。

追加したGame ObjectにAudio Sourceコンポーネントを追加していきます。先ほど作成したGame Objectを選択して音源をInspectorにドラッグアンドドロップします。

NomalのInspectorウィンドウにAudio Sourceコンポーネントが追加された

同様に他のGame Objectについても音源を追加してください。
音源が追加できたら、入室時に音がならないように音源のGame ObjectはOFFにしておきます。

Shift + クリックで範囲指定できるので、まとめてOFFにしてください。

必要なアニメーションについて

必要なアニメーションは以下の4つです。

  1. 以下全ての音源をOFFにするアニメーション(初期化用 Idle.anim)

  2. NomalをONにするアニメーション(標準 Nomal.anim)

  3. Sound_1をONにするアニメーション(ランダム用 Sound_1.anim)

  4. Sound_2をONにするアニメーション(ランダム用 Sound_2.anim)

  5. Sound_3をONにするアニメーション(ランダム用 Sound_3.anim)

アニメーションを作成

ここからアニメーションを作成していきます。Projectウィンドウの開いてるところを右クリックしてCreate > Aniamtionでアニメーションファイルを作成します。

New Animationのファイル名をIdleに変更してVRC Avataor Descriptorのあるアバターのルートにドラッグアンドドロップします。するとAvator RootというAnimator Controllerが自動的に生成され、アバターのAnimatorとして設定されます。

ヒエラルキーのAvatorRootを選択後、Animation ウィンドウを開くと録画ボタンが有効になっているかと思います。これを押してアニメーションを作成していきます。

録画ボタンを押したら先ほど作成したGameObjectを全てOFFにするために、Inspectorウィンドウから左上のチェックボックスをOFFにした状態にしてください。そうすると、アニメーションが自動的に録画されます。NomalからSound_3まで全てOFFにしたアニメーションを作成してください。

次に、先程と同様の手順で新しいアニメーションファイルをNomalと名前をつけて作成します。その後、Avator Rootにドラッグアンドドロップします。録画するアニメーションを切り替える際は、アニメーションウィンドウのプルダウンをクリックすると切り替えることができます。

NomalをONにするアニメーションを作成します。

Sound_1からSound_3についてもそれぞれ1つだけONにするアニメーションを作成してください。

メニューとパラメータの作成

Ransel_MenuとRansel_Parameterを作成します。

作成方法はプロジェクトを右クリックしてCreate > VRChat > Avatars からそれぞれ作成できます。

パラメータをIsNomalとSOUND_NUMBERの2つ追加します。IsNomalのDefaultをONにしておいてください。

【パラメータ】[Bool] IsNomalと[Int] SOUND_NUMBERを追加します。

メニューを作成します。Add ControlからTypeをToggleに指定して、でIsNomalのパラメータを切り替えられるようにしてください。

【メニュー】IsNomalをToggleできるようにしておきます。

アニメーターの作成(失敗パターン)

Animator Controllerに苦手意識がある方が多いと思います。私もそうでした。一生懸命組んでもちゃんと動いてくれなかったりしたら結構ショックですよね。Physboneとランダムを組み合わせてなにかやってみたいと思ったとき、次のAnimatorが考えられるかと思います。
※次の例はローカルで動くけど、他の人から見たときははちゃんと動いていない同期の失敗パターンになります。

パラメータの作成

[bool] IsNomal ・・・ Nomalとランダム切り替え用のパラメータ。持っている値はtrueまたはfalse。
[bool] buzzer_IsGrabbed ・・・ Physboneにつけたパラメータ。持ったときを検知。持っている値はtrueまたはfalse。
[float] buzzer_Stretch ・・・Physboneにつけたパラメータ。どれぐらい伸びたかを検知。持っている値は0から1の範囲。
[int] SOUND_NUMBER ・・・ ランダムに分岐させるためのの数字を持たせるパラメータ。初期値は0。

BuzzerSoundというレイヤーを追加して以下のような遷移を作成しました。
まず、プレイヤーが入室したらIdleで全ての音源をOFFにした状態にします。
仕組みとしては、ブザーが引っ張られたときbuzzer_Stretchの数字が増え、buzzer_IsGrabbedがtrueになります。ブザーから手を離すとbuzzer_Stretchの数字が減り、buzzer_IsGrrabedがfalseになります。
これを利用して、ブザーが引っ張られたとき、IsNomalがtrueの場合は、NomalのGameObjectをONにする。ブザーから手が離されたらIdleに戻りNomalのGameObjectがOFFになる。といったことを表現しています。

矢印の条件に行きは赤字で、帰りは青字で表現しています。

次にVRC Avator Pramater Driveを使ってSOUND_NUMBERを1~3の値になるように設定します。

Idleを選択して、Add Behavior > VRC Avatar Primeter Driverと入力して選択する。
Local Onlyにチェック
Addを選択してプルダウンからTypeをRandomにし、SOUND_NUMBERを1~3になるようにする。

先程のメニューとパラメータをAvator Descriptorに設定し、Av3Emulatorを追加した状態でテストしてみました。引っ張ったときの様子です。

IsNomal=trueのとき、
Nomalのステートに移動し、ヒエラルキーウィンドウのNomalのGame ObjectがONになり、音源が再生される。
IsNomal=falseのとき、
Sound_1~3のいずれかのステートに移動し、音源が再生される。
Sound_1に移動する様子。
IsNomal=falseのとき、
Sound_1~3のいずれかのステートに移動し、音源が再生される。
Sound_2に移動する様子。


IsNomal=falseのとき、
Sound_1~3のいずれかのステートに移動し、音源が再生される。
Sound_3に移動する様子。

ランダムなステートの移動ができた!

と思って意気揚々とアップロードしてみんなに自慢しようとしたところ、自分が聞こえてる音と周りが聞こえている音が違っていたり、聞こえなかったりしているようでした。

なぜかというと・・・

VRC Avatar Prameter Driverのランダムも、Phsyboneもローカル計算のため、自分のパソコンでは計算できていても、その情報が他のプレイヤーにも伝わらない(同期されない)からです。

同期されるパラメータと同期されないパラメータ

ここで、同期されるパラメータと同期されないパラメータについて確認したいと思います。

https://www.youtube.com/watch?v=wGpJnHl6lo0
より引用
7:37あたり

同期するパラメータは上記の通り、Expression Parameterに自身で登録したパラメータや、ハンドサイン、3点トラッキングの状態、アバターの座標、PoseしたPhysboneの状態となります。
同期しないパラメータは、Animator Parameter(Animator内で設定するパラメータ)、Contactの判定結果、トラッカー以外のIKボーン、GrabしているPhysbone、触っているPhysboneとなります。

では、どうやってランダムやPhysboneのGrabやStretchの状態を同期すればいいのか悩むかと思いますが、上記の同期するいずれかのパラメータとPhysboneやランダムの値を連携させることで何だか同期できるような気がしませんか?

ハンドジェスチャーでも同期してもいいのですが、もっと賢い方法があります。Expression Parameterは同期に対応しているので、そこに同期用のパラメータを登録して、それを使って遷移することで他に人からみたときでも同じ遷移ができる、つまり、同期ができるようになります。

また、具体的にどうやって連携させるかというとVRC Avator Parameter Driverを使って、同期しないパラメータを使った遷移が発生したときに、同期用のパラメータを設定することで、同期しないパラメータと同期するパラメータを連携することができます。

大事なのは、VRC Avator Parameter Driverを使うと遷移が発生したタイミングでパラメータの書き換えが行われるという機能に着目することです。

アニメーターの作成(成功パターン)

それでは、同期に対応したAnimator Controllerを作成していきましょう。
設計の方針としては以下のとおりです。

  • IsLocal変数を使ってローカルで同期用のパラメータと同期しないパラメータを計算・連携させる。

  • 上記の同期用のパラメータを使って、アニメーションを遷移させる。

これから、同期パラメータ設定用のレイヤーと、同期完了後のパラメータを使ってアニメーションを再生するレイヤーの2つを作成していきます。

以降、同期パラメータ設定用のレイヤーのことを、コントローラーレイヤー。同期完了後のパラメータを使ってアニメーションを再生するレイヤーを、プレイヤーレイヤーと呼ぶことにします。

パラメータの設定

パラメーターを一つ追加します。

[bool] IsLocal ・・・ VRChatが用意している標準のパラメーター。ローカルPCで動いている場合にtrueとなる。他のプレイヤーから見るとfalseとなっている。
[bool] IsNomal ・・・ Nomalとランダム切り替え用のパラメータ。持っている値はtrueまたはfalse。
[bool] buzzer_IsGrabbed ・・・ Physboneにつけたパラメータ。持ったときを検知。持っている値はtrueまたはfalse。
[float] buzzer_Stretch ・・・Physboneにつけたパラメータ。どれぐらい伸びたかを検知。持っている値は0から1の範囲。

名前をわかりやすく変更します。
[int] SYNC_SOUND_NUMBER ・・・ ランダムに分岐させるためのの数字を持たせる同期用のパラメータ。初期値は0。0の場合何も再生しない。1の場合、Nomalを再生する。2~4の場合、Sound_1~3を再生する。

コントローラーレイヤーの作成

BuzzerControlerレイヤーを作成して以下のような遷移にします。
基本的には引っ張られたときにIdleから遷移して、手が離されたときにIdleに戻るという動作は同じです。

IsLocalは自身のみtrueとなるので、LOCAL GATEは他のプレイヤーからは遷移されない。これを使ってローカルでのみで同期用のパラメーターの計算と設定を行う。
コントローラーレイヤーのアニメーションはについては、ローカルでの変数の計算用のレイヤーなので、何も設定せずにNoneで構いません。

VRC Avatar Prameter を以下のように設定します。

Local Onlyにチェックを入れておいてください

IsNomal=trueの場合、同期用のパラメータを1にして、普通のブザー音がなるようにしています。
Idleから遷移して戻ったときに同期用のパラメーターを0になるようにすることで、手が離されたときに音源の再生を停止するということが可能になります。IsNomal=falseの場合、2~4のランダムな値を使ってSound_1~3を再生するようにしています。

プレイヤーレイヤーの作成

SYNC_SOUND_NUMBERを使って1~4の間で条件を設定します。初期値の0が含まれないので0の場合はどこにも遷移しません。

プレイヤーレイヤーでは基本的にVRC Avatar Parameter Driverは使用しない。理由は、同期変数の処理をコントローラーレイヤーに役割として持たせているから。

テスト

IsNomal=trueのとき
コントローラーレイヤーで、SYNC_SOUND_NUMBER1となり
プレイヤーレイヤーでNomalに遷移する。
すると、普通のブザー音がなります。

コントローラーレイヤー
IsNomal=true
SYNC_SOUND_NUMBER=1
プレイヤーレイヤー
IsNomal=true
SYNC_SOUND_NUMBER=1


IsNomal=falseのとき
コントローラーレイヤーで、SYNC_SOUND_NUMBER2から4の値となり、プレイヤーレイヤーでSound_1~3のいずれかに遷移する。
ここで、ランダムに設定したブザー音がなります。()

コントローラーレイヤー
IsNomal=false
SYNC_SOUND_NUMBER=2
プレイヤーレイヤー
IsNomal=false
SYNC_SOUND_NUMBER=2

もう一度ブザーを引っ張り直して見た結果、今度はSYNC_SOUND_NUMBERが3になりましたので、Sound_2に設定した音がなります。

コントローラーレイヤー
IsNomal=false
SYNC_SOUND_NUMBER=3
プレイヤーレイヤー
IsNomal=false
SYNC_SOUND_NUMBER=3

終わりに

ここまで読んでいただきありがとうございました!
長文となってしまい申し訳ございません。

ただランダムの動作と同期の処理のアニメーターについて書こうと思ってたのですが、気づいたら8000文字以上になっていました笑(レポートでもなかなかこの文字数は書いたことはない)

もし記事の中で間違っていることがあれば随時指摘していただけると嬉しいです!

これまでの内容をunitypackageとして出力しましたので、実際に動作を確認したい方は以下からダウンロードしてください。

もしこの記事が役に立ったり、勉強になったとおもったら、ぜひコメントやいいねをお願いします。反応してくれると、頑張ってよかった―!と今後の励みになります!

内容は以上です!

それでは、良いUnityライフを。そして、良いVRChatライフを!

₺ƾ₺ƾkesera2がお届けしました!

たくさんのフォローお待ちしております♪


この記事が気に入ったらサポートをしてみませんか?