環境
- VRCSDK3-WORLD-2021.02.23.11.40_Public
- UdonSharp_v0.19.2
- Unity 2018.4.20f1
実現したいこと
- カラオケ喫茶ワールドの中にリバーブがある空間と無音空間を作りたい
- カラオケで騒ぎつかれた人が静かな空間でチルアウトできるように
-
Audio Reverb Zoneだと境界線が丸くなるので「この四角い部屋の中は無音!」というのが難しい?
Audio Listener って?
VRChatでいうとアバターの「耳」にあたるオブジェクト
ここにフィルタをかけることで外から聞こえる音にエフェクトをかけることができる
VRChat 特有の仕様(?)
-
ワールド作成時に
ActiveなAudio Listenerはどこに設置していてもアバターと合わせて動く- この仕様を利用して空間を移り変わるごとに
Audio Listenerの有効/無効を切り替えることで音響効果をつける - おそらく
Audio Listenerを1つにしてコンポーネントをつけ外しすることでも実現可能
- この仕様を利用して空間を移り変わるごとに
大まかな手順
- 当たり判定を作成し
Is Triggerを有効にする - 当たり判定配下あたりに
Audio Listenerコンポーネントを含むGameObjectを作成し好きな音響効果をつける - 1.で作った当たり判定の出入りで
Audio Listenerの有効/無効を切り替える(UdonSharp)
当たり判定を作成し Is Trigger を有効にする
- エフェクトを効かせたい空間を覆うように Cube オブジェクトを作成
- Is Triggerを有効にする(1敗)
- Mesh Renderer を無効にするかコンポーネントごと削除する(以下の図では有効になっている)
2. 当たり判定配下あたりに Audio Listener コンポーネントを含む GameObject を作成し好きな音響効果をつける
- 当たり判定の近傍(出来たら子)に
Create Emptyを行い空オブジェクトを作成 -
Audio Listenerと好きなフィルターを付ける(今回はHPFとLPFを両方つけて無理やり音量を下げている)
3. 1.で作った当たり判定の出入りで Audio Listener の有効/無効を切り替える(UdonSharp)
- 1.で作成した当たり判定オブジェクトに
Udon Behavior(Script)コンポーネントを追加 - New Program ボタンをクリック
- Create Script ボタンをクリックし好きな場所にC#ファイルを作成する
- 以下のように実装
SilentArea.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
// SilentArea
public class SilentArea : UdonSharpBehaviour {
void Start()
{
this._silentAreaListener = this.transform.Find("Listener").gameObject;
this._silentAreaListener.SetActive(false);
}
// UdonSharpBehaviour
public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
// ローカルのプレイヤーの場合のみ切り替え
if (player.isLocal)
{
this._silentAreaListener.SetActive(true);
}
}
public override void OnPlayerTriggerExit(VRCPlayerApi player)
{
// ローカルのプレイヤーの場合のみ切り替え
if (player.isLocal)
{
this._silentAreaListener.SetActive(false);
}
}
// Private
private GameObject _silentAreaListener;
}
- 保存してビルドが通ったら挙動を確認する
ソースコードの解説
変数宣言
- 操作する
Audio Listenerコンポーネントを含むGameObjectを宣言しておく - 外部から余計な参照をされないように
privateで宣言
void Start()
- ワールド読み込み時に呼ばれる関数
-
this._silentAreaListenerの初期化を行う -
this.transform.find("<GameObjectの相対パス>").gameObjectで操作するGameObjectにアクセス- ちなみにヒエラルキーの親にアクセスする場合は
this.transform.parent
- ちなみにヒエラルキーの親にアクセスする場合は
- ワールド起動時に
AudioListenerを無効化することでAudioListenerがアバターにくっつく
public override void OnPlayerTriggerEnter(VRCPlayerApi player) ほか
- On〇〇系列の操作やタイミングに関連する関数は凡そ
UdonSharpBehaviourから継承されている模様 - エリアにアバターが出入りするタイミングで
this._silentListenerの有効/無効を切り替えることでエフェクトをかけている - この関数は ワールドのどのアバターがエリアに出入りしても発火する
playerのisLocalがtrueであることを検証しないとほかのアバターの出入りで音の聞こえ方が変化してしまうため注意(1敗)
その他注意点
-
Audio Listenerを検知エリアと同じGameObjectに設定すると ゲームオブジェクトを無効にした際に当然ながら二度とエリアが発火しなくなるため注意(1敗) - エリアの出入りを行うとノイズが混じることがある
- エフェクトの切り替わりがぱっつりすぎて波形が切れるためか、
Audio Listenerが一瞬ダブるからか... - 「徐々に洞窟に入っていく」といった表現には不向き
- エフェクトの切り替わりがぱっつりすぎて波形が切れるためか、
まとめ
-
Audio Listenerと各種フィルターを利用することで四角い空間にエフェクトをかけることができる UdonSharpBehaviorのOnPlayer〇〇関数を利用するときは必ずplayer.isLocalを検証しましょう
わからなかったこと・知りたいこと
- 単純に音量を下げたい場合にはどうすればよかったのか?
- 今はFPFとLPFをつけて無理やり音量を下げているため音が軋んで聞こえる
- 空間内部のアバター同士は普通に会話を楽しませたい
-
Audio Listenerを切り離してアバターの座標と音声のやり取り座標を切り離せないか?- アバターの発話を担当している (おそらく)
Sound Sourceの取得方法がわからなかった
- アバターの発話を担当している (おそらく)
-


