Three.js は Web 上で最も広く使われている WebGL ライブラリであり、WebXR エコシステムの多くの土台でもあります — A-Frame はこれをラップし、WebXR サンプル の多くは直接 three.js で書かれています。A-Frame が宣言的で Babylon.js が全部入りのエンジンであるのに対し、three.js はその中間に位置します。シーングラフを完全に制御できる、無駄のない命令的なツールキットでありながら、WebXR の配線は数行で済みます。

threejs.org · ドキュメント · WebXR 例 · GitHub (MIT, r170, 105k★)

three.js が XR にもたらすもの

WebXR サポートのすべては renderer.xr(three.js の WebXRManager)に存在します。有効化はプロパティ 1 つ、セッション開始はボタンヘルパー 1 つです:

  • renderer.xr.enabled = true でレンダリングがヘッドセットのステレオビューと両眼投影を通るようになります。
  • VRButton / ARButtonthree/addons/webxr/ 内)が navigator.xr.requestSession、機能ネゴシエーション、入退室 UI を処理します。
  • renderer.setAnimationLoop(fn)requestAnimationFrame を置き換えます — XR を理解し、ヘッドセットのフレームレートで両眼ペアごとに 1 回ティックします。
  • renderer.xr.getController(i)XRHandModelFactory が、コントローラーと関節付きハンドを通常の Object3D としてシーンに登場させます。

スターター — HTML 1 ファイル、ビルド不要

最新の three.js は ES モジュールとして配布されます。インポートマップで CDN からライブラリを読み込むため、スターター全体がバンドラ不要の 1 ファイルになります:

<!DOCTYPE html>
<html><body style="margin:0">
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
} }
</script>
<script type="module">
  import * as THREE from 'three';
  import { VRButton } from 'three/addons/webxr/VRButton.js';

  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(innerWidth, innerHeight);
  renderer.xr.enabled = true;                          // ① WebXR 有効化
  document.body.appendChild(renderer.domElement);
  document.body.appendChild(VRButton.createButton(renderer)); // ② Enter VR

  const scene  = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(70, innerWidth / innerHeight, 0.1, 100);
  scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 3));

  const cube = new THREE.Mesh(
    new THREE.BoxGeometry(0.4, 0.4, 0.4),
    new THREE.MeshStandardMaterial({ color: 0x23f0ff }));
  cube.position.set(0, 1.5, -2);
  scene.add(cube);

  renderer.setAnimationLoop(() => {                    // ③ XR 対応の描画ループ
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
  });
  addEventListener('resize', () => {
    camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix();
    renderer.setSize(innerWidth, innerHeight);
  });
</script>
</body></html>

この印を付けた 3 行が、デスクトップの WebGL ページとヘッドセットアプリの違いのすべてです。VRButtonARButton に替える — ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] }) — だけで、代わりに immersive-ar パススルーセッションが始まります。

コントローラーとハンド

どちらも同じマネージャから得られます。コントローラーをシーンオブジェクトとして追加し、その select イベントを購読します。ハンドメッシュはファクトリ経由で読み込みます:

import { XRHandModelFactory } from 'three/addons/webxr/XRHandModelFactory.js';

const controller = renderer.xr.getController(0);
controller.addEventListener('select', () => { /* トリガー */ });
scene.add(controller);

const hands = new XRHandModelFactory();
const hand = renderer.xr.getHand(0);
hand.add(hands.createHandModel(hand, 'mesh'));
scene.add(hand);

グリップやレイポインタには renderer.xr.getControllerGrip(i)XRControllerModelFactory を使い、物理コントローラーのモデルを描画します。webxr_vr_draggingwebxr_xr_ballshooter の例が定番のリファレンスです。

デプロイと対象デバイス

WebXR には HTTPS が必要です。A-Frame の記事 と同じ静的ホストと cloudflared クイックトンネルのワンライナーがそのまま使えます:

cloudflared tunnel --url http://localhost:8080

イベントで利用できるヘッドセットと、three.js での到達方法:

  • Meta Quest 3 — Meta Quest Browser:フル WebXR — immersive-vrimmersive-ar パススルー、ハンドトラッキング、AR 機能。最もスムーズな対象です。
  • PICO 4 Ultra Enterprise — PICO Browser が同じ標準 Android ベースで WebXR を公開します。ハッカソンには複数台を用意しています。標準型ヘッドセットと同様、Enter VR の動作を早めに確認してください。
  • Apple Vision Pro — visionOS の Safari:ハンドおよび transient-pointer 入力での immersive-vr(WebXR の AR モジュールはありません)。操作はハンド中心に。
  • Snap SpectaclesBrowser Lens:ハンドトラッキング付き immersive-ar、演算は制限あり。

なぜ 2.5 日のハッカソンに向くのか

  • 共通言語 — ほとんどの WebXR スニペット、Stack Overflow の回答、AI 生成コードは three.js を前提とするため、情報がどこにでもあります。
  • ビルド不要 — インポートマップのスターターは 1 ファイルで動きます。Vite が要るのはプロジェクトが大きくなってから。
  • 1 シーンであらゆるヘッドセット — 同じ URL が Quest 3、PICO、Vision Pro、Spectacles で動きます。
  • スプラットとビデオへの道 — three.js は同じシーングラフで ガウシアンスプラット を読み込み、ステレオビデオ を再生します。WebXR ビューアとインタラクティブなデモが 1 つのコードベースを共有できます。

関連リンク

ご質問は お問い合わせ ページからどうぞ。

// ニュース一覧へ戻る