VRChatで個展を開く(その1)

現在、VRChat内で個展を開催しようと画策中です。
2018年現在、VRChatでは有志が交流やコンテンツの展示を目的とした数えきれないほどのイベントが開催されていますが、よく考えたら空間の確保や移動時間のコストがほぼゼロなので「個人でどこまでできるか」を考えた結果こういう形態になりました(予定)。

現在の内装はこんな感じで、作品を際立たせるためにもワールド自体はあえて現実に即した作りになっています。特に都内某所の某メディアアート展示室に影響を受けてる感じになっています(が、普通アート関係の内装といったら白地の壁+木目調の床なのでこれ以外の選択肢もない気がする……)。

 

作品は全部で20点くらい+αで、シェーダを使って何かしらする作品が約半数、何らかの形でインタラクト可能なものが数割、現代アート的なものが数点、外部サービス+Webサーバ+WebPanel+シェーダでゴリゴリ実装した作品が数点になる予定です。
みんな大好きGPUパーティクルを使った作品も展示予定です。

 

開催形態については絶賛作業中のためまだ未定ですが、WebPanelが復活次第(ここ重要)、金土日の3日間の深夜帯にワールドをFriends+で開ける感じになるかと思います(昼間については「VRで潜る体力が残ってれば開く」程度の心持ち)。
WebPanelが復活する見込みがなさそうであれば代替の展示物をネタを捻り出して作るのでもうちょっと延びます。
ちなみに今の所半分くらいの作品は完成しています。

以下展示関係のツイート。

vrchat-time-shadersの解説

最近公開したvrchat-time-shadersについて、ざっくりとした解説を書いときます(訳: 今月のいいブログネタがなかった)。特に技術的にトリッキーなことは何もしていませんが、WebPanelを使ったコンテンツ制作の参考になれば幸いです。

前振り

VRChatではユーザがUnityで作成したコンテンツを「ワールド」または「アバター」としてアップロード・使用することができます。しかし、サポート体制・セキュリティ・UXの質の確保などの理由(推測)によって使用できるComponentが厳しく制限されています。

具体的には、

に加えてVRCSDKに含まれるComponentが使用できます。

重要なこととして、ここにはC#やJSでコーディングするためのScriptが含まれていません。よって、ワールド作成でなにかと需要がある(と筆者が思っている)時計を普通に実装しようという場合は、Scriptを使わない方法でなんとか実装する必要があります。
一方で、ワールドで使用できるComponentにはユーザサイドで任意コードの実行ができるものが存在します。
VRC_WebPanelです。
これは本来はワールド上でWebページを表示するためのものですが、当然ページ内にJavaScriptを仕込めば好きなコードが実装できます。vrchat-time-shadersではこれを利用して時計を実装しています。

実現方法

VRC_WebPanel経由で時計を実装するためにはおおまかに分けて3つのステップが必要になります。

  1. JavaScriptで時刻情報を(何らかの形で)ページに表示する
  2. CameraとRenderTextureでシェーダに時刻情報を伝達する
  3. シェーダで時刻をデコードし、時計として表示する
以下順番に説明します。
ちなみに、WebPanelで直接時計を描画すればシェーダ等を使わなくても普通に実装できますが、このパッケージでは「Webサーバを立てることなく好きなデザインの時計を(Unity内だけの作業で)配置することができるようにする」「時計に関する汎用的なシェーダを提供する」という目的で公開しています。具体的な応用例としてはこちら

1. 時刻情報の表示

JavaScriptのDateオブジェクトから実行されているPCの時刻を取得してdivの色を変えることで表示します。現在のバージョンでは、RGBの各色をそれぞれ1 bitとして使用して、

  • 黒 → 0 (0b000)
  • 赤 → 1 (0b001)
  • 緑 → 2 (0b010)
  • 黄 → 3 (0b011)
のようにそれぞれのマスが3 bitを表現するようにしています。詳しいマスの中身についてはWikiをご参照ください。具体的なJSによる実装はこちら
原理的には1つのマスにつきRGB各色を8 bitとして8*3=24 bitの表現が可能なのですが、WebPanelにはガンマ値の設定ミスによって白飛びが発生する(した?)バグがあるため、このような現象が発生する可能性を考慮して0-1のみの情報として取り出しています。

2. RenderTextureへの伝達

UnityにおけるRenderTextureはカメラの描画先として設定することができるテクスチャです。ここではWebPanelの目の前にCameraを設置して描画先をRenderTextureとすることでJSからの情報をテクスチャにコピーします。カメラの設定は以下のようにして平行投影でWebPanelを捕捉します。
カメラ設定

3. 時刻情報のデコード

RenderTextureの特定の点をサンプリングして時刻情報をデコードします。以下はサーフェスシェーダ内で時(0-23)を_TexWPの左上の2個のマス目から取得する例です。

これにより時刻情報が整数値として取得でき、これを利用してUV座標の決定・回転・クリッピング・補完等を行うことで時計やSkyboxなどを描画します。

おまけ: 現実の天気に応じて雨を降らせる

y23586’s Portfolioではログイン時の東京の天気に応じて雨や雪が降るようになっています。これはgithub上で公開されているインタフェースを1マス分拡張して天気情報を取得できるようにすることで実現しています。
こうして私達のもとに届けられる
天気情報を含むページのURLはhttps://y23586.net/extra/vrchat-time-shaders-api/v1w/です。基本的に、WebPanelのURLをこれに切り替えるだけで動作します。
※このページではlivedoorのお天気Webサービスを使用しています。このAPIはなぜかアクセストークン不要・アクセス回数制限不明のものなので私も雰囲気で使っているのですが、y23586.net自体とlivedoorの両方に過度な負荷をかけない範囲でご利用ください。また、このAPIは予告なく変更・削除する場合があります。

 

一番右下のマスが以下のように対応しています。
天気数値
晴れ0
曇り1
小雨2
3
大雨4
5
以下のようなサーフェスシェーダを書くと「特定の天気のときだけ表示する」といったことが実現できます。