チュートリアル: 3D オブジェクトの操作

babylon.js を使用して、Mixed Reality エクスペリエンスの 3D オブジェクトと操作を作成する方法について説明します。 このセクションでは、まず、オブジェクトを選択するときにキューブの面を描画するなど、簡単なことから始めます。

このチュートリアルでは、以下のトピックを取り上げます。

  • 操作を追加する方法
  • WebXR イマーシブ モードを有効にする
  • Windows Mixed Reality シミュレーターでアプリを実行する
  • Android Chrome でアプリを実行およびデバッグする

開始する前に

前のチュートリアルの手順では、シーンが作成された基本的な Web ページを作成しました。 ホストしている Web ページを編集用に開いておきます。

<html>
<head>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <style>
        body,#renderCanvas { width: 100%; height: 100%;}
    </style>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
    <script>
        const canvas = document.getElementById("renderCanvas");
        const engine = new BABYLON.Engine(canvas, true);
        
        const createScene = function() {
            const scene = new BABYLON.Scene(engine);
            scene.clearColor = new BABYLON.Color3.Black;
            
            const alpha =  Math.PI/4;
            const beta = Math.PI/3;
            const radius = 8;
            const target = new BABYLON.Vector3(0, 0, 0);
            
            const camera = new BABYLON.ArcRotateCamera("Camera", alpha, beta, radius, target, scene);
            camera.attachControl(canvas, true);
            
            const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
            
            const box = BABYLON.MeshBuilder.CreateBox("box", {});
            box.position.x = 0.5;
            box.position.y = 1;
            
            return scene;
        };
        
        const sceneToRender = createScene();
        engine.runRenderLoop(function(){
            sceneToRender.render();
        });
    </script>
</body>
</html>

操作を追加する

  1. まず、キューブがランダムな色で描画されるように、キューブを作成するコードを更新しましょう。 これを行うには、キューブに素材を追加します。 素材を使用すると、色とテクスチャを指定でき、他のオブジェクトを覆うことができます。 素材がどのように表示されるかは、シーンで使用される 1 つまたは複数のライトと、どのように応答するように設定されているかによって異なります。 たとえば、diffuseColor は、アタッチされているメッシュ全体に色を広げます。 次のコードを追加します。

    const boxMaterial = new BABYLON.StandardMaterial("material", scene);
    boxMaterial.diffuseColor = BABYLON.Color3.Random();
    box.material = boxMaterial;
    
  2. これでキューブがランダムな色で描画されたので、次の操作を追加しましょう。

    • キューブがクリックされたときに色を変更する
    • 色が変更された後でキューブを移動する

    操作を追加するには、アクションを使用する必要があります。 アクションは、イベント トリガーへの応答として起動されます。 たとえば、ユーザーがキューブをクリックしたときなどです。 BABYLON.ActionManager をインスタンス化して、特定のトリガーのアクションを登録するだけです。 BABYLON.ExecuteCodeAction では、キューブがクリックされたときに JavaScript 関数が実行されます。

    box.actionManager = new BABYLON.ActionManager(scene);
    box.actionManager.registerAction(new BABYLON.ExecuteCodeAction(
        BABYLON.ActionManager.OnPickTrigger, 
        function (evt) {
            const sourceBox = evt.meshUnderPointer;
    
            //move the box upright
            sourceBox.position.x += 0.1;
            sourceBox.position.y += 0.1;
    
            //update the color
            boxMaterial.diffuseColor = BABYLON.Color3.Random();
        }));
    
  3. Web ページの最後のコードは次のようになります。

    <html>
    <head>
        <script src="https://cdn.babylonjs.com/babylon.js"></script>
        <style>
            body,#renderCanvas { width: 100%; height: 100%;}
        </style>
    </head>
    <body>
        <canvas id="renderCanvas"></canvas>
        <script>
            const canvas = document.getElementById("renderCanvas");
            const engine = new BABYLON.Engine(canvas, true);
    
            const createScene = function() {
                const scene = new BABYLON.Scene(engine);
                scene.clearColor = new BABYLON.Color3.Black;
    
                const alpha =  Math.PI/4;
                const beta = Math.PI/3;
                const radius = 8;
                const target = new BABYLON.Vector3(0, 0, 0);
    
                const camera = new BABYLON.ArcRotateCamera("Camera", alpha, beta, radius, target, scene);
                camera.attachControl(canvas, true);
    
                const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
    
                const box = BABYLON.MeshBuilder.CreateBox("box", {});
                box.position.x = 0.5;
                box.position.y = 1;
    
                const boxMaterial = new BABYLON.StandardMaterial("material", scene);
                boxMaterial.diffuseColor = BABYLON.Color3.Random();
                box.material = boxMaterial;
    
                box.actionManager = new BABYLON.ActionManager(scene);
                box.actionManager.registerAction(
                    new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, 
                    function (evt) {
                        const sourceBox = evt.meshUnderPointer;
                        sourceBox.position.x += 0.1;
                        sourceBox.position.y += 0.1;
    
                        boxMaterial.diffuseColor = BABYLON.Color3.Random();
                    }));
    
                return scene;
            };
    
            const sceneToRender = createScene();
            engine.runRenderLoop(function(){
                sceneToRender.render();
            });
        </script>
    </body>
    </html>
    

WebXR のイマーシブ エクスペリエンスを有効にする

キューブの色が変更されたので、イマーシブ エクスペリエンスを試せるようになりました。

  1. この手順では、グラウンドを導入します。 キューブが宙に浮き、底部にフロアが表示されます。 グラウンドは次のように追加します。

    const ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 4});
    

    これにより、単純な 4 x 4 m のフロアが作成されます。

  2. WebXR サポートを追加するには、Promise の結果をもたらす createDefaultXRExperienceAsync を呼び出す必要があります。 return scene; ではなく、次のコードを createScene 関数の末尾に追加します。

    const xrPromise = scene.createDefaultXRExperienceAsync({
        floorMeshes: [ground]
    });
    return xrPromise.then((xrExperience) => {
        console.log("Done, WebXR is enabled.");
        return scene;
    });
    
  3. これで createScene 関数によって、シーンの代わりに Promise が返されるので、createSceneengine.runRenderLoop を呼び出す方法を変更する必要があります。 </script> タグの直前に配置されるこれらの関数の現在の呼び出しを、次のコードに置き換えます。

    createScene().then(sceneToRender => {
        engine.runRenderLoop(() => sceneToRender.render());
    });
    
  4. Web ページの最後のコードは次のようになります。

    <html>
    <head>
        <script src="https://cdn.babylonjs.com/babylon.js"></script>
        <style>
            body,#renderCanvas { width: 100%; height: 100%;}
        </style>
    </head>
    <body>
        <canvas id="renderCanvas"></canvas>
        <script>
            const canvas = document.getElementById("renderCanvas");
            const engine = new BABYLON.Engine(canvas, true);
    
            const createScene = function() {
                const scene = new BABYLON.Scene(engine);
                scene.clearColor = new BABYLON.Color3.Black;
    
                const alpha =  Math.PI/4;
                const beta = Math.PI/3;
                const radius = 8;
                const target = new BABYLON.Vector3(0, 0, 0);
    
                const camera = new BABYLON.ArcRotateCamera("Camera", alpha, beta, radius, target, scene);
                camera.attachControl(canvas, true);
    
                const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));
    
                const box = BABYLON.MeshBuilder.CreateBox("box", {});
                box.position.x = 0.5;
                box.position.y = 1;
    
                const boxMaterial = new BABYLON.StandardMaterial("material", scene);
                boxMaterial.diffuseColor = BABYLON.Color3.Random();
                box.material = boxMaterial;
    
                box.actionManager = new BABYLON.ActionManager(scene);
                box.actionManager.registerAction(
                    new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, 
                    function (evt) {
                        const sourceBox = evt.meshUnderPointer;
                        sourceBox.position.x += 0.1;
                        sourceBox.position.y += 0.1;
    
                        boxMaterial.diffuseColor = BABYLON.Color3.Random();
                    }));
    
                const ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 4, height: 4});
    
                const xrPromise = scene.createDefaultXRExperienceAsync({
                    floorMeshes: [ground]
                });
    
                return xrPromise.then((xrExperience) => {
                    console.log("Done, WebXR is enabled.");
                    return scene;
                });
            };
    
            createScene().then(sceneToRender => {
                engine.runRenderLoop(() => sceneToRender.render());
            });
        </script>
    </body>
    </html>
    
  5. 上記のコードにより、ブラウザー ウィンドウに次の出力が生成されます: WebXR シーン

Windows Mixed Reality シミュレーターで実行する

  1. 以前に Windows Mixed Reality シミュレーターを有効にしていない場合は、これを有効にします。

  2. 右下隅にある [イマーシブ VR] ボタンを選択します: [イマーシブ VR] ボタン

  3. この操作によって、以下に示すように、[Windows Mixed Reality シミュレーター] ウィンドウが起動します: Mixed Reality ポータル

  4. キーボードの W、A、S、D の各キーを使用して、それぞれ前、後、左、右に動かします。 シミュレーションされた手を使用してキューブを対象にし、キーボードの Enter キーを押してクリック操作を実行します。 キューブの色が変更され、新しい位置に移動されます。

注意

キューブを対象とする場合は、上の図に示すように、ハンド レイの端 (白丸) がキューブと交差していることを確認します。 詳細については、「手を使ったポイントとコミット」を参照してください。

Android デバイスで実行およびデバッグする

Android デバイスでのデバッグを有効にするには、次の手順を実行します。

前提条件

  • 開発用コンピューター上でセキュリティで保護されたコンテキスト (https:// またはローカルホスト上のポート フォワーディング経由) で静的 HTML ページを提供する Web サーバー。 たとえば、静的 HTML ファイルを提供する単純な軽量 Web サーバーとして serve npm パッケージを活用します。詳細について npm serve を確認してください

  • 元々 Google Play ストアが装備されたデバイスで、Android 7.0 以降を実行している必要があります

  • 開発用ワークステーションとデバイスの両方に搭載された最新バージョンの Google Chrome

  • WebXR を実行するためにデバイスが正しく構成されていることを検証するには、デバイス上のサンプル WebXR ページを参照します。 次のようなメッセージが表示されます。

    お使いのブラウザーは WebXR をサポートしており、適切なハードウェアを使用していれば、仮想現実および拡張現実のエクスペリエンスを実行できます。

  1. Android デバイス上で開発者モードと USB デバッグを有効にします。 お使いのバージョンの Android でこれを行う方法については、「デバイスの開発者向けオプションを設定する」の公式ドキュメント ページを参照してください

  2. 次に、USB ケーブルで、開発用コンピューターまたはノート PC に Android デバイスを接続します

  3. 開発用コンピューター上で Web サーバーが実行していることを確認します。 たとえば、Web ホスティング ページ (index.html) が格納されているルート フォルダーに移動し、次のコードを実行します (serve npm パッケージを使用していると想定)。

    serve
    
  4. 開発用コンピューター上で Google Chrome を開き、アドレス バーで次のテキストを入力します。

    chrome://inspect#devices [Chrome USB デバッグ] ウィンドウ

  5. [USB デバイスの検出] チェックボックスが有効になっていることを確認します

  6. [ポート フォワーディング] ボタンをクリックし、ポート フォワーディング が有効になっており、次のように localhost:5000 というエントリが含まれていることを確認します: [Chrome ポート フォワーディング] ウィンドウ

  7. 接続されている Android デバイスで、[Google Chrome] ウィンドウを開き、 http://localhost:5000 を参照すると、キューブが表示されます

  8. 開発用コンピューターの Chrome にはデバイスと、そこで現在開かれている Web ページの一覧が表示されます: [Chrome Inspect] ウィンドウ

  9. http://localhost:5000 のエントリの横にある [Inspect] ボタンをクリックします:  [Chrome DevTools デバッグ] ウィンドウ

  10. Chrome DevTools を使用してページをデバッグします

重要なポイント

このチュートリアルから得られる最も重要なポイントは次のとおりです。

  • babylon.js を使用すると、JavaScript を使用したイマーシブ エクスペリエンスの作成が簡単になります
  • 仮想シーンを作成するには、ローレベルのコードを作成する必要も、新しいテクノロジについて学習する必要もありません
  • WebXR でサポートされているブラウザーで Mixed Reality アプリケーションを構築でき、ヘッドセットを購入する必要はありません

次のステップ

お疲れさまでした。 一連の babylon.js チュートリアルを完了し、次の方法を学習しました。

  • 開発環境をセットアップする
  • 結果を表示する新しい Web ページを作成する
  • 基本的な 3D 要素を作成して操作するための babylon.js API
  • Windows Mixed Reality シミュレーターでアプリケーションを実行およびテストする

Mixed Reality JavaScript 開発の詳細については、Javascript 開発の概要に関するページを参照してください。

別の babylon.js チュートリアルをお探しの場合は、babylon.js を使用して VR 空間でピアノを構築する方法について、ピアノ構築に関するチュートリアル シリーズをご覧ください。