Programming in VRChat

VRChat でのプログラミングについて調べたことの書き溜め

WebPanel

メモ書きレベルですが、分かったことを放出:

概要

  • 簡単な紹介
    • VRC_WebPanel は web browser の画面を VR ワールド内に提供するコンポーネント
    • 現在(2018/2)作りかけのようでドキュメントや Unity エディタ上で表示されるが動作しない機能はいろいろある模様。限定的には動作する。
  • 使えた使い方
    • Quad を作って、それに VRC_WebPanel を追加する
    • 表示するコンテンツは HTTP(S) アクセスできるところ(要するにネット上)に置く。アセットに置いてワールドに同梱することは出来ない追記:まったく動かないわけではない模様下記参照)
    • インタラクティブにする(要するにマウスカーソル相当の操作を可能にする)には Collider を有効にしておく必要がある
    • 操作アクションは trigger のエディタで action 追加で Events from Scene から追加する。SetWebPanelURI は動作した。

現状

  • ブラウザとしては動く
    • マウス操作、テキストフィールドへのキーボード入力は可能
  • アセットとしてブラウズするファイルをバンドルすることは出来ない模様。
    • HTTP アクセスできる場所に配置する必要がある。
    • SDK にサンプルとして含まれている VRCSDK\Examples\Sample Assets\WebRoot はロードできる
    • 追記(2018/4/3): HTMLファイルなら同梱させることが出来たとのこと: https://twitter.com/Kanata_VRC/status/980831077571809280
    • 追記(2018/7/18):動作が不安定で正常に読み込まれないことがあるとのこと: https://twitter.com/Kanata_VRC/status/1012870109470191617 (初期化のタイミングが VRChat クライアント側とブラウザプロセス側でレースコンディションになっている(?))
  • SDK 同梱サンプルは不完全
    • browser.html は動かない。
      • これは、web page の中に、ブラウザを作ろうとするもの
      • (PC のブラウザで開くと動くので、何か実装依存の部分と衝突している? x-frame-options か?)
      • ドキュメントに "iframes will be removed" と書いてあるが、このブラウザ部分がその iframe なんだが(?)
    • サンプルのシーン Example-Actions に WebPanel 関連のものがあるが、そもそも WebPanel を含むオブジェクトが配置されていない。
      • 推測:prefab を提供するつもりだが不具合のため外されている?
  • コンポーネントとしての制御 action が上手く動かない
    • ドキュメント https://docs.vrchat.com/docs/vrc_webpanel によれば WebPanelReload などのアクションを備えているはずだが
    • (自分の使い方なのか、現状実装がそうなのか、切り分け不完全)
    • 追記:ドキュメントと実装がずれている?trigger のエディタで action 追加で Events from Scene から追加した SetWebPanelURI は動作した。
    • 追記:RPC の各機能は Synchronize URI を有効にしてマルチ環境で共有状態にしないといけないらしい。(未確認) http://vrcworld.wiki.fc2.com/wiki/VRC_WebPanel
  • JavaScript を通じて VRChat のワールドのオブジェクトなどへアクセスできるようにする意向があるようだが、いまいち動かない(後述)
  • JavaScript で click イベントは取れるが、なぜか連続で4ないし3回呼ばれる
  • javascript schemeURI を SetWebPanelURI で与えると、任意の JavaScript コードを実行できる(ブックマークレットと同じ手法)。JavaScript function を VRChat のトリガーシステムから駆動できる。
  • RPC 一覧
    • SetWebPanelURI
    • SetWebPanelVolume
    • WebPanelForward
    • WebPanelBackward
    • WebPanelReload

参考

URLのhash部分を使って、マルチプレイヤー環境で上手く情報伝達する方法の解説: VRChatのWebPanelでバッファ同期する変数を使う

引用:

SetWebPanelURIはBroadcastTypeをAlwaysにしていても最後の1回しか実行されない(ログを見るとAlwaysBufferOneと同じく、いったんイベントが削除されてから再登録されているので、おそらくこれは不具合ではなく仕様)

これは「URIを次々と変えていっても最終的に表示されるのは一つだから必要なURIは最後の一つだけだろう」という余計なお世話なのだろうか。

内部の推測

JavaScript API

  • Coherent UI の仕様 https://coherent-labs.com/Documentation/unity/dc/d3f/namespaceengine.html
  • VRC_WebPanel の Coherent UI の組み込み
    • つまり JavaScript での見え方
    • document に対して 'onBindingsReady' イベントが追加定義されている
    • window.engine オブジェクトが追加されている。これが Coherent UI の engine そのもの。
    • 'onBindingsReady' 後、engine に対して "ListBindings" を call 出来る。
      • (返ってきた promise により)call 出来る名前の配列が返ってくる。
  • それにより得られた機能を呼んでみたところの現状実装
    • 引数なしでプリミティブを返してくるものは呼べた。
      • 例: VRCSDK2.Networking.GetServerTimeInSeconds
    • 引数がプリミティブなものは一部機能した
      • 例: VRCSDK2.Networking.GoToRoom
    • オブジェクトを返してくるものは機能しない。
      • ログファイルを見るとエラー発生のスタックトレース出ている場合がある。
      • エラーログも出さずに、だんまりになる場合もある。
    • 全体として、C#オブジェクトと JavaScript オブジェクトのブリッジが、書かれていない(あるいは無効化されている)ように見える、という感じ。
  • バインディングの詳細メモ
    • call が返す Promise の error
      • 引数に Array でエラーの情報が来る。
      • 要素はこんな感じ {"first": "ArgumentType", "second": "Missing argument 0"}
      • ただし call する名前を間違えると Promise が error も実行してくれない。
    • JS object から C# オブジェクトへの変換 エラー
      • __Type 指定がない場合 { first: "ArgumentType", second: "Could not determine managed type from JavaScript value" }
      • __Type で指定した型名不一致 { first: "ArgumentType", second: "Could not determine managed type from __Type {type-name}" }
      • プロパティ名の不一致 { first: "ArgumentType", second: "Type {type-name} has no property {prop-name}" }

“ポエム”

  • 個人的にはまっとうに動いたら最も楽しそう、と思う機能。
  • ユーザースクリプトを動かすサンドボックスとして、ブラウザに同梱されている JavaScript エンジンを使うってのありじゃないかなぁ。
  • ちゃんとブリッジされたら、JavaScript の世界が、VRChat 世界とリアル世界をつないでくれることになるわけで。
    • 直接インタラクトできないワールド間をトンネルするって、なにそれ SF 心をくすぐる。
    • リアル世界に置いた IoT 機器が Internet を通じて VRC_WebPanel のトンネルを抜けて VR ワールドに影響する、というものを構築できる。またその逆も。
    • VR world 間の通信も可能だ。