Babylon.js で Meta Quest 3 で動く ES6 + Vite + TypeScript 開発構成を GitHub Codespaces で作ったメモ 2024 年 3 月版

Babylon.js で Meta Quest 3 で動く ES6 + Vite + TypeScript 開発構成を GitHub Codespaces で作ったメモ 2024 年 3 月版です。

今後も仕様が変わる可能性があるので 2024 年 3 月版としてます。

2024/03/28 に少し改修しました。

  • ビルドに絡むコードと設定を追加

Github リポジトリの作成

新しいリポジトリを作ります。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_11.png

今回は名前を babylonjs-vite-es6-sample-202403 にしました。自分で作業するものなので Private でつくります。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_10.png

.gitignore は JavaScript の環境なので Node にしてます。

License や README はお好みで。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_09.png

作成できました。

GitHub Codespaces の作成

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_07.png

リポジトリができたらリポジトリのページから GitHub Codespaces を起動します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_00.png

自分の作業しやすいようにテーマをダークにしました。

いろいろインストール

おもに WebXR Demos and Examples | Babylon.js Documentation を参考に進めます。

npm create vite@latest

のコマンドをターミナルで入力します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_05.png

Need to install the following packages:
create-vite@5.2.3
Ok to proceed? (y) y
✔ Project name: … vite-project
✔ Select a framework: › Vanilla
✔ Select a variant: › TypeScript

Vanilla で TypeScript で指定します。プロジェクト名は vite-project です。

  cd vite-project
  npm install

指示に従って vite-project フォルダに入って、インストールします。

npm install @babylonjs/core @babylonjs/loaders

vite-project 内でインストールします。

index.html の修正

vite-project のルートにある index.html を以下のように修正します。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + TS</title>
    <style>
      html,
      body {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }

      canvas {
        width: 100%;
        height: 100%;
        touch-action: none;
      }

    </style>
  </head>
  <body>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

追加した仕組みとしては、画面いっぱいに広げる CSS を追加しました。

src/main.ts の修正

WebXR Demos and Examples | Babylon.js Documentation にある main.ts のソースを調整したものを上書きします。

import "./style.css";
 
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera.js";
import { Color3 } from "@babylonjs/core/Maths/math.color.js";
import { Engine } from "@babylonjs/core/Engines/engine.js";
import { EnvironmentHelper } from "@babylonjs/core/Helpers/environmentHelper.js";
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight.js";
import { Mesh } from "@babylonjs/core/Meshes/mesh";
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder.js";
import { Scene } from "@babylonjs/core/scene.js";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
import { Vector3 } from "@babylonjs/core/Maths/math.vector.js";
import { WebXRDefaultExperience } from "@babylonjs/core/XR/webXRDefaultExperience.js";
 
// Required for EnvironmentHelper
import "@babylonjs/core/Materials/Textures/Loaders";
 
// Enable GLTF/GLB loader for loading controller models from WebXR Input registry
import "@babylonjs/loaders/glTF";
 
// Without this next import, an error message like this occurs loading controller models:
//  Build of NodeMaterial failed" error when loading controller model
//  Uncaught (in promise) Build of NodeMaterial failed: input rgba from block
//  FragmentOutput[FragmentOutputBlock] is not connected and is not optional.
import "@babylonjs/core/Materials/Node/Blocks";
 
// XR ボタンを右下に表示させるために必須
import "@babylonjs/core/Helpers/sceneHelpers";
import { mainUVVaryingDeclaration } from "@babylonjs/core/Shaders/ShadersInclude/mainUVVaryingDeclaration";

const main = async () => {
  // Create a canvas element for rendering
  const app = document.querySelector<HTMLDivElement>("body");
  const canvas = document.createElement("canvas");
  app?.appendChild(canvas);
  
  // Create engine and a scene
  const babylonEngine = new Engine(canvas, true);
  const scene = new Scene(babylonEngine);
  
  // Add a basic light
  new HemisphericLight("light1", new Vector3(0, 2, 0), scene);
  
  // Create a default environment (skybox, ground mesh, etc)
  /*
  const envHelper = new EnvironmentHelper(
    {
      skyboxSize: 30,
      groundColor: new Color3(0.5, 0.5, 0.5),
    },
    scene,
  );
  */
  
  // Add a camera for the non-VR view in browser
  const camera = new ArcRotateCamera("Camera", -(Math.PI / 4) * 3, Math.PI / 4, 10, new Vector3(0, 0, 0), scene);
  camera.attachControl(true);
  
  // Add a sphere to have something to look at
  const sphereD = 1.0;
  const sphere = MeshBuilder.CreateSphere("xSphere", { segments: 16, diameter: sphereD }, scene);
  sphere.position.x = 0;
  sphere.position.y = sphereD * 2;
  sphere.position.z = 0;
  const rMat = new StandardMaterial("matR", scene);
  rMat.diffuseColor = new Color3(1.0, 0, 0);
  sphere.material = rMat;
  
  // Setup default WebXR experience
  // Use the enviroment floor to enable teleportation
  /*
  WebXRDefaultExperience.CreateAsync(scene, {
    floorMeshes: [envHelper?.ground as Mesh],
    optionalFeatures: true,
  });
  */
  
  const xr = await scene.createDefaultXRExperienceAsync({
    uiOptions: {
      sessionMode: "immersive-ar",
    },
    optionalFeatures: true,
  });
  
  
  // Run render loop
  babylonEngine.runRenderLoop(() => {
    scene.render();
  });
}

main();
  • EnvironmentHelper の部分は Meta Quest のパススルーになっていてもフロアメッシュで全体を覆ってしまうので消しています。
  • sceneHelpers を導入して scene クラスで createDefaultXRExperienceAsync を使えるようにしています
  • 参考コードにある WebXRDefaultExperience.CreateAsync は一旦コメントアウトしています
  • npm run build 時にトップレベルの await/async をしていると警告が出るので main 関数で処理を囲っています

Vite でテストサーバー起動

npm run dev

ターミナルで上記のコマンドを実行してVite でテストサーバー起動します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_14.png

ポートタブで今回のサーバ起動されていることを確認します。

ブラウザで表示してみる

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_15.png

こちらの今回のサーバをこちらのボタンをクリックしてブラウザで開きます。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_16.png

ブラウザでうまく動作していることが確認できました!

Meta Quest 3 で表示してみる

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_14.png

ポートタブで Meta Quest 3 でも表示できるように公開します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_13.png

右クリックでメニューを出して ポートの表示範囲 > Public をクリックします。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_06.png

こちらのボタンで URL をコピーします。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_03.png

Meta Quest Developer Hub で Meta Quest 3 をつなぎます。(この手順の前に Meta Quest Developer Hub で Meta Quest 3 が動作するようにしておきましょう。)

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_12.png

Meta Quest Browser 項目に URL を入力して Open をクリックします。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_02.png

Meta Quest 3 をかぶるとこのような画面で URL が開いていて Continue をクリックします。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_04.png

うまく表示されたので右下の眼鏡ボタンをクリックして XR として起動します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_01.png

下部にダイアログが出るので許可します。

babylonjs-es6-vite-ts-github-codespaces-for-meta-quest-3-setting-202403_08.jpg

パススルーが効いた景色になるので、ちょうど頭上あたりを除くと、さきほどブラウザで表示されている赤いボールが出てきます。ブラウザで表示するときと XR で表示するときでカメラ位置が移動しているような挙動ですね。

ビルドするときは tsconfig.json を修正

このまま npm run build してしまうと、未使用のクラス参照がチェックされて警告が出てビルドできないので tsconfig.json を修正します。

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"]
}

こちらを、

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,

    /* Linting */
    "strict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"]
}

noUnusedLocals を false にして保存します。これでビルドの準備も完了です。

npm run build

ターミナルで上記のコマンドを実行してビルドを実行すると成功するはずです。

とにもかくにも、このようにBabylon.js で Meta Quest 3 で動く ES6 + Vite + TypeScript 開発構成を GitHub Codespaces で作ることができました~!