CrossRoad

AR、MR、VR、Babylon.jsを中心とした技術ブログ。 If you're non-Japanese native guys, check "English" category.

【2019/6/26 更新】Babylon.jsでOculus Questのコントローラを任意のモデルに変更する方法


2019/6/26 追記

デフォルトのTouchコントローラのモデルが残ってしまう問題の解決方法を追記しました。


Babylon.jsでVRコンテンツを作り、VRヘッドセットでアクセスすると、コントローラもVR空間に表示されます。

ただし、5月に発売したばかりのOculus Questでアクセスすると、Oculus Touchのコントローラが表示されます。 (Babylon.js v4.1.0の場合)

そこで、今回はコントローラを別のモデルに差し替える方法をまとめました。

1. 前提:コントローラのモデルは、拡張子.babylon形式で格納されている

通常、Babylon.jsでコンテンツ開発する時、コントローラの指定をコードで書くことはありません。これはBabylon.jsのライブラリ側で定義されているためです。

GitHub - BabylonJS/Babylon.js: Babylon.js is a powerful, beautiful, simple, and open game and rendering engine packed into a friendly JavaScript framework.

これを確認するには、上記のGithubからgit cloneしたものを調べます。

assets/mesh/controllers/oculus の中にある、left.babylonとright.babylonがOculus Touchのコントローラです。このように表示されます。

  • src/Gamepads/Controllers/oculusTouchController.ts
    public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
        let meshName;

        // Hand
        if (this.hand === 'left') {
            meshName = OculusTouchController.MODEL_LEFT_FILENAME; // left.babylon
        }
        else { // Right is the default if no hand is specified
            meshName = OculusTouchController.MODEL_RIGHT_FILENAME; //right.babylon
        }

        SceneLoader.ImportMesh("", OculusTouchController.MODEL_BASE_URL, meshName, scene, (newMeshes) => {
            /*
            Parent Mesh name: oculus_touch_left
            - body
            - trigger
            - thumbstick
            - grip
            - button_y
            - button_x
            - button_enter
            */

            this._defaultModel = newMeshes[1];
            this.attachToMesh(this._defaultModel);
            if (meshLoaded) {
                meshLoaded(this._defaultModel);
            }
        });

ただし、モデルの読み込みには.glbも対応しています。今回はglb形式のファイルを使いました。

2. コントローラの代わりとなるモデルの調整方法

Blenderのver2.8を使います。2.79ではテクスチャが出力されないためです。以下のswordモデルを使わせていただきました。

sting sword fbx free

これは、以前Babylon.js Editorの使い方紹介でも使いました。

【2018/12/16更新】UnityのようなGUIでWebGLコンテンツが作れるBabylon.js Editorの基本的な使い方 - CrossRoad

2.1 scaleはBlender基本図形のCylinderのscale=0.4程度に合わせる

Blenderで読み込んだら、Cylinderを表示させます。次にswordモデルをインポートします。

A sword model and cylinder  has been imported in blender 2.8

VR空間で使用するQuestのコントローラはCylinderよりも少し小さいので、swordの大きさを調節します。ここでは、swordが4つのパーツに分かれています。Lameという剣部分だけ後で使いたいので、それ以外をjoin機能で結合します。

次に、swordのモデルのscaleをx,y,z全て0.015まで下げます。これでだいたいCylinderと同程度になり、Oculus Questで表示しても違和感ないサイズになります。

2.2 swordの柄部分のoriginを変更する

Blenderには、オブジェクトの原点を変更する機能があります。以下の画像に書いた(1)〜(4)に沿って進めます。

How to change origin of 3DCG object in Blender 2.80

  • (1) OutlinerからCameraとCylinderを削除

  • (2) 3D cursorを選択 (ver2.79ではデフォルト表示されていましたが、2.80からは矢印アイコンと独立しています)

  • (3) swordの柄部分を選択

How to change origin of 3DCG object in Blender 2.80 2

  • (4) Origin to 3D Cursorを選択

How to change origin of 3DCG object in Blender 2.80 3

  • (5) Reset All to Default Valuesを選択

これで、Questで表示されるコントローラの位置がswordの柄付近になります。

2.3 glb形式でexportする

BlenderのFile / Export / gltf 2.0 を選択すると、左下に出力設定が表示されます。1つのモデルしか表示していない場合は特に設定変更不要です。

これで、大きさを調整したswordのglbファイルが出力されます。

3. コントローラのモデルを差し替える

作成したモデルをソースコードから参照できる場所に配置し、下記のコードを書きます。


2019/6/26 追記

@YSAIQSさん情報に基づき、コードを修正しました。ありがとうございます。


            var rightSwordMesh;
            BABYLON.SceneLoader.ImportMeshAsync("", "filePath", "sword.glb", scene).then(function(result) {
                rightSwordMesh = result.meshes[0];)
            });
 vrHelper.webVRCamera.onControllersAttachedObservable.add(e => {
        vrHelper.webVRCamera.rightController.attachToMesh(rightSwordMesh);
});

4. 動作確認する

このようになります。

同じように調整することで、Oculus Questのコントローラも表示できます。 Questのコントローラモデルは@mirako_maruchoさんご提供のものを使わせていただきました。

Oculus Questのコントローラ配布場所

sketchfab.com

5. 現状の問題点

(解決)5.1 Oculus Touchのコントローラのモデルが消えない

今回右手側を差し替えましたが、VRモードになった瞬間に元のOculus Touchのコントローラが残ってしまいます。消す方法がわかったら追記します。


2019/6/26 追記

解決しました。以下のコードで消えます。

var vrHelper = scene.createDefaultVRExperience({controllerMeshes:false});
//var vrHelper = scene.createDefaultVRExperience();

createDefaultVRExperience()の引数を空にする、あるいはcontrollerMeshes:trueにすると、デフォルトコントローラのメッシュが表示されます。falseにすると非表示になります。

左右のコントローラのモデルを変更する処理を書いた状態で、controllerMeshesを変更するとこのようになります。

A result of controllerMeshes option in Babylonjs


5.2 (解決)ボタンを押すとページが停止する

2019/6/26更新

ボタンを押すと止まっていましたが、これはonBeforeRenderObservable(毎フレーム呼ばれる)の中で呼んでいたためでした。呼び場所を変えることで発生しなくなりました。

しかし、コントローラを別のモデルに変更し、controllerMeshes:falseを使うと、うまくコントローラが表示されません。

また、controllerMeshes:trueにするとボタン入力はできるのですが、デフォルトのOculus Touchコントローラが残ったままになります。

この辺はもう少しBabylonjsの理解が進んだら解決できる気がするので、一旦保留しようと思います。

6. おわりに

最初、attachToMesh関数に気づかず、Babylon.jsのコード自体をビルドして確認していました。例えば、このツイートで表示したときはBabylon.jsのコードをビルドしてから表示させたものです。

Babylon.jsをビルドすると色々できることも多いので、次回はビルド方法について書く予定です。