環境
- 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
の取得方法がわからなかった
- アバターの発話を担当している (おそらく)
-