CrossRoad

XRを中心とした技術ブログ。 Check also "English" category.

Babylon.jsのWebVRモードと通常モードを切り替える方法

English version is here

How to switching mode between WebVR and 2D view in Babylon.js - CrossRoad

Babylon.jsを使うと、以前紹介したようにWebVRコンテンツも開発できます。

Babylon.jsでWindows Mixed Realityヘッドセットのアプリを作る方法 - CrossRoad

WebVRモードにするには、はじめに表示した画面右下のVRヘッドセットマークを選択するだけです。

Babylon.jsのWebVRサンプル画面のVRモードボタン

しかし、VRモードから通常の2Dモードに戻すボタンはありません。そのため、今まではページを再読み込みしていました。また、意外なことに調べても情報が出てきませんでした。

そこで、今回はVRモードから2Dモードに戻す方法を調べました。

動作環境です。

  • Chrome : 71.0.3578.98
  • Babylon.js : 3.3

1. Babylon.js サンプルコードには、VRモード切り替えボタンのソースコードが載っていない

WebVRモードの最もシンプルなソースコードはこちらです。アクセス後、Zipボタンでhtmlを含む全ソースコードを取得できます。

https://www.babylonjs-playground.com/#VIGXA3#7

取得したindex.htmlには、html <button> タグがありません。また、Babylon.jsのHPにあるDocumentをみても見つけることができませんでした。 html <button>はサンプルコードのindex.htmlの中にはなく、babylon.jsから生成されるようです。

2. Chrome Developer Toolで設定されたイベントを読み取る

そこで、Chrome Developer Toolを使って、表示中のWebページからどこで宣言されているかを探しました。下記の記事を参考にさせていただきました。

要素に設定されているイベントを調べよう - ゆずめも

Chrome上で、その他のツール / デベロッパーツールを選ぶと、Chrome Developer Toolを起動できます。このような画面です。

Screenshot of Chrome Developer Tools

今回、WebVRボタンが押された時のイベントを読み取りたいので、画面の1〜5のように進めました。

1 : 画面の要素を選択できるようにする

2 : WebVRボタンを選択

3: Event Listenerを選択

4 : Clickイベントを選択

5: handlerを右クリック

ここで、Show function definition を選択すると、イベントハンドラと紐づいたソースコードが表示されます。

Event handled method of WebVRbutton in BJS

ここで、enterVR()、exitVR()というメソッドを発見できました。

3. Babylon.jsのSearchで使い方を確認する

Babylon.jsのHPは、全てのページの右上にSearchエリアがあります。

Search area of Babylon.js

それぞれのメソッドを調べた結果、VRExperienceHelperのメソッドであることがわかりました。

4.実装して動作を確認する

最低限のコードを下記に置きました。

BJS_SwitchToNormal_WebVR/index.html at master · flushpot1125/BJS_SwitchToNormal_WebVR · GitHub

これは、360Photoのサンプルをベースとして、WebVRのコードを追加し、さらにActionManagerによってキーイベントで動くようにしています。

参考
How to do 360 Photo - Babylon.js Documentation

Use the WebVR experience helper - Babylon.js Documentation

Use Actions - Babylon.js Documentation

サンプルコードでは、キーボードの"s"でWebVRモードに移動、"e"でノーマルモードに移動(=WebVRモード終了)としています。動きは以下の動画の通りです。

5. Tips

5.1 enterVR()は、イベントリスナー系の中で呼ばないとエラーが出る

たとえば、こんなコードを書くとfullscreen errorが出ます。

var map = {}; //object for multiple key presses
            scene.actionManager = new BABYLON.ActionManager(scene); // for key event
            scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnKeyDownTrigger, function (evt) {
                map[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
            }));
//          
            scene.registerAfterRender(function () {

                if (map["S"] ) {// pushed key "S"
                    vrHelper.enterVR();
                };
                if (map["E"] ) { // pushed key "E"
                    vrHelper.exitVR();
                };
            });
Uncaught (in promise) TypeError: fullscreen error
    at Function.e.RequestFullscreen (babylon.js:16)
    at e.enterFullscreen (babylon.js:16)
    at e.enterVR (babylon.js:16)
    at Object.callback ((index):124)
    at e.notifyObservers (babylon.js:16)
    at t.render (babylon.js:16)
    at (index):166
    at e._renderLoop (babylon.js:16)

VRモードになり、両眼表示にはなるのですがフルスクリーンになりません。色々試したところ、ActionManagerというイベントハンドラと組み合わせることでRequestFullscreenを呼ぶことができました。

5.2 exitVR()を呼ぶだけではフルスクリーンを解除できない

これも色々試したところ、exitFullscreen()を一緒に呼ぶことで解決しました。

6. おわりに

fullscreen関係のAPIは、Babylon.jsというよりHTML5の仕様なのですが、enterVRやexitVRの中ですでに呼ばれてしまっていたので解決策がわからず、思ったより時間がかかりました。
ひとまずこれで、WebVRと2D Viewの切り替えが簡単になりました。次回はOculus GoでWebVRを表示したり、コントローラを扱う方法を書いてみる予定です。