カイワレスタイル

ゲーム、アニメ、プログラム、興味のあることをツラツラと。

三日坊主を止めるな2のVJシステム(Boze Jockey System)についての仕組み解説

はじめに
 
去る2020年 12月28日、VRChat内で「三日坊主を止めるな2」という謎のイベントが開催されました。
イベントの様子は、おきゅたんbotさんに配信して頂きました。
アーカイブはこちらから↓
 
自分は、このイベントの音声映像配信とVJ演出周りを担当しました。
今回は、これらの仕組みの解説をしていきます。
一旦、上のアーカイブでライブの映像を見てからのほうが、理解しやすいと思います。

システム構成図&概要

まずはざっくりとしたシステム構成図です。

f:id:kaiware007:20210124153256p:plain

続いて、ざっくりとした流れです。

  1. SyncRoomで三日坊主さん、らくとあいすさん、Nikoさん、myxyさんの音声を集めて、UnityOBSに送る

  2. Unity製の自作VJアプリでVJ映像と制御信号を混ぜた映像をSpout出力

  3. OBS側でUnityの映像とSyncRoomの音声をTopazChatで配信する

  4. VRChat内の会場のTopazChatPlayerで映像と音声を受信

  5. 映像テクスチャをなんやかんやしてVJする

※ちなみに、OBSでSpoutを使うには下記のプラグインを使用しました。

 

github.com

※OBSで映像と音声をよしたかさん作のTopazChat 2.0 Player経由でVRChatのライブワールドに送ります(よしたかさん、VoxelKeiさん、本当にありがとうございます)

自作VJアプリ「Boze Jozkey System」について

 自作VJアプリでは、スクリーンに映すBoze映像と、VJ制御用の信号を映像に変換してSpout出力する仕組みになっています。

アプリ自体の画面は、下の画像のようになっていてワールド内の演出の操作用のUIパネルと、再生するBoze映像の切り替えパネルになっています。
f:id:kaiware007:20201231200454p:plain
演出のオンオフやパラメータの変更などは、MIDIコンに対応させていました。
使用していたMIDIコンは、みんな大好きnanoKONTROL2です。
ただ、当時のVRChatとの相性が悪く、先にVRChatを起動してからMIDIコンを繋がないと高確率でVRChatがフリーズする問題があったので注意が必要です(今は大丈夫かな?)
演出のオンオフとMIDIコン上のボタンのLEDが連動するようにしたかったので、Unity側からもMIDI信号を送れるようにするためRtMidi for Unityを使用させていただいてます。
 
Boze映像は、Hap形式という低負荷(ただしファイルサイズが大きくなりがち)エンコードに変更しています。これにより、動画の頻繁な差し替えをしても全然カクついたりしなくなりました。
また、UnityでのHap動画の再生はKlakHapを使用させていただいてます。
 使用したBoze映像は、こちらでまとめています(宣伝)
 
それから、SyncRoomから受け取った音声の波形を解析して演出のトリガーにしたりする仕組みは、Laspを使用させていただいてます。
 
振り返ると、かなりのミドルウェアkeijiro takahashi神のお力を借りていますね。ありがたや…ありがたや…🙏
 

制御信号について

ワールド内の演出を配信映像から制御するために、演出のオンオフ状態やパラメータの値を「色」に変換してRenderTextureに書き込んでいます。
テクスチャ上の各ピクセルは、RGB各色が8bit(計24bit、アルファチャンネルがあるときは32bit)の数値で表されています。
コンピュータ上では「色」もただの数値です。
VJ演出のパラメータも数値です。オンオフも1、0に置き換えられる数値です。
なので、テクスチャにそのまま書き込んでしまいます。
 
テクスチャにデータを書き込む方法については、memexぴぼさんが超詳細な記事を書いてくれているので、そちらをご参照ください。めちゃくちゃ参考になりました。
 
と、丸投げもよろしくないので、実際に使用したUIのパラメータをRenderTextureに書き込むサンプルを用意しました。
ピボさんのに比べると、8bit(256段階)分の情報しか書き込んでないので精度はいまいちですが、短時間で激しく変化するVJの制御ではほとんど問題なかったです。
また、 圧縮で細かいピクセルが潰れることを考慮して、16x16の領域に書き込んでます。
それから、細かい調査はしてないですが、書き込む色は、赤よりはグレースケールのほうが綺麗に色が出ました。赤は、だいぶ潰れて黒い感じになってしまいました。

扱っている制御信号の種類とUI

  • 低音、中音、高音の音量
    LASPで波形解析した音域ごとの音量。キックの音に合わせた演出をやりたくて、しきい値以下の音量は切り捨てるようにしてたりします。
    また、UI上でそれぞれの音量の可視化と、DynamicRangeの調整をできるようにしてます。

    f:id:kaiware007:20210130154018p:plain

  • 各種エフェクトのオンオフ
    会場の巨大Boze頭や後ろのうねうね、般若心経文字、パーティクルなどの演出のオンオフ、エフェクトの掛かり具合を調整するスライダーのUIです。

    f:id:kaiware007:20210130153949p:plain

  • ラクルBozeライト
    ワールド内のミラクルBozeライト(禍々しいサイリウムのようなもの)のUIです。固定色を選択したり、虹色に変化するようにしたりできます。この設定だけ「ちゃんとした色」としてをテクスチャに書き込んでいます。

    f:id:kaiware007:20210130154552p:plain

Boze動画

Hap動画のリストから、2つの動画を再生して、真ん中のスライダーでブレンドしたり、再生速度を個別に変えたりできます。

f:id:kaiware007:20210130155030p:plain

 VJアプリから出力する映像

制御信号とBoze動画を下図のような配置でSpout出力しています。
配信の安定化や低遅延を考えて、640x360という低解像度で送ってます。
f:id:kaiware007:20201231194527p:plain
 最終的な配信画像はこんな感じ

f:id:kaiware007:20210130155734p:plainSpoutの出力をOBSで受け取り、SyncRoomから受け取った音と一緒に配信しています。

ライブ会場のVJ

配信で送った映像をワールド内のTopazChat 2.0 Playerで受信し、映像をカメラで撮影してRenderTextureに書き込みます。
そのRenderTextureを各種オブジェクトのマテリアルにセットして、各種シェーダーで制御信号部分の色を読み取って色々演出をします。
例えば、巨大Boze頭のシェーダーでは、トゲトゲエフェクトのオンオフの領域の色を読み取ってGeometryシェーダーでポリゴンを分割してトゲ状に変化させたりしています。
また、ミラクルBozeライトでは、ライトの色の領域を読み取って、ライトの色を変化させつつ、低音の領域の値も見て、音に合わせて光の強弱をつけるようにしています(コレが結構気持ちよさに効いてる)
会場の左右の巨大スクリーンには、配信映像のBoze動画の部分だけをクロップして表示しています。 
会場内の演出一覧
  •  巨大Boze頭オブジェ&ウネウネ
    ・トゲトゲ
    ・映像が映る
    ・空間グリッチ
    ・般若心経が表面に現れる
    ワイヤーフレームになる
  • 左右のスクリーン
  • 空間に3D般若心経が浮かび上がる
  • ラクルBozeライトの音と光の連動、色の変化
  • ステージ上にBoze粒子(パーティクル)が漂う
  • Boze粒子の軌道の切り替え

まとめ

システムのキモは制御信号を色として映像に載せて送り、ワールド内のシェーダーで配信映像のテクスチャから値を取る部分です。
配信の部分に関しては、TopazChatを使わなくても、TwitchやYoutubeでも全然可能だと思います。
VJシステムと、ワールド内のVJ演出用のシェーダーの2つを並行して開発するのはなかなか大変でしたが、ライブのあとの達成感が心地よかったです。
 
みんなもUnityでVJしよう!