WebARを自前のJavaScriptコードで実装したい開発者にとって、Three.js + WebXR Device APIの組み合わせは最も柔軟な選択肢のひとつです。本記事では、Three.jsを使ったAR空間への3Dオブジェクト配置から、hit-test(平面検出)の実装、パフォーマンス最適化まで、実践的なコード例を交えて解説します。
Three.js + WebXRとは?
Three.jsはWebGL上で3Dグラフィックスを扱うための人気JavaScriptライブラリです(GitHubスター数:90,000以上)。WebXR Device APIはW3Cが標準化を進めるブラウザAPIで、ARおよびVRセッションをウェブから直接起動できます。
Three.jsはv128(2021年)からWebXRのサポートを強化しており、THREE.WebXRManagerを通じてARセッションの管理・レンダリングをシームレスに行えます。8th Wallのような月額有料サービスとは異なり、ライセンス費用ゼロで高度なWebARを実装できる点が最大の魅力です。
対応ブラウザ・デバイス
- Android Chrome 81以降: WebXR AR完全対応(最も安定)
- iOS Safari: WebXR ARは未対応(2024年現在)。iOSではAR.jsまたはModel Viewer経由でのAR Quick Lookを利用
- Samsung Internet: 部分対応
環境構築
npmプロジェクトでの導入
npmを使う場合は以下のコマンドでThree.jsをインストールします。
npm install three
Viteを使ったプロジェクトでのセットアップ例:
npm create vite@latest my-webar -- --template vanilla
cd my-webar && npm install three && npm run dev
CDNで素早く試す
手早くプロトタイプを作るにはCDN経由が便利です。HTMLファイルに以下を追加するだけで利用できます。
<script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.164/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.164/examples/jsm/"}}</script>
ARセッション開始の基本コード
WebXR ARセッションを開始する最小構成のコードです。
index.html(ARボタン):
<!DOCTYPE html>
<html><body>
<button id="ar-btn">ARを起動</button>
<script type="module" src="./main.js"></script>
</body></html>
main.js(ARセッション初期化):
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera();
document.getElementById('ar-btn').addEventListener('click', async () => {
const session = await navigator.xr.requestSession('immersive-ar', {
requiredFeatures: ['hit-test']
});
renderer.xr.setSession(session);
});
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
hit-testで床面を検出して3Dオブジェクトを配置する
hit-test機能を使うと、カメラが向いている先の実世界の平面(床・テーブルなど)を検出し、その位置に3Dオブジェクトをスナップ配置できます。
// hit-testソースを取得
let hitTestSource = null;
session.requestReferenceSpace('viewer').then(refSpace => {
session.requestHitTestSource({ space: refSpace }).then(source => {
hitTestSource = source;
});
});
// アニメーションループ内でhit-testを実行
renderer.setAnimationLoop((timestamp, frame) => {
if (frame && hitTestSource) {
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) {
const hit = hitTestResults[0];
const pose = hit.getPose(referenceSpace);
// poseの位置にオブジェクトを移動
myObject.position.setFromMatrixPosition(new THREE.Matrix4().fromArray(pose.transform.matrix));
}
}
renderer.render(scene, camera);
});
レンダリング最適化のポイント
モバイルでのWebARはCPU・GPU・バッテリーへの負荷が高いため、以下の最適化が重要です。
- ポリゴン数を抑える: ARオブジェクトは10,000ポリゴン以下を目標にする
- テクスチャ圧縮: KTX2/BasisUフォーマットを使用してテクスチャサイズを最大80%削減
- LOD(Level of Detail):
THREE.LODクラスを使い、距離に応じてポリゴン数を切り替え - シャドウ無効化: AR環境ではリアルタイムシャドウをオフにする(
renderer.shadowMap.enabled = false) - フレームレート制限:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))でピクセル比を制限
AR.jsとの使い分け
| 項目 | Three.js + WebXR | AR.js |
|---|---|---|
| 対応ブラウザ | Android Chrome(iOS不可) | iOS Safari含む広範囲 |
| 実装難易度 | 中〜高 | 低(A-Frameタグ記述) |
| マーカーレスAR | ◎ hit-test対応 | △ 限定的 |
| マーカーAR | △(追加実装必要) | ◎ NFTマーカー対応 |
| カスタマイズ性 | ◎ 高い | △ 制約あり |
| おすすめ用途 | 高品質ARアプリ開発 | iOS対応が必要なキャンペーン |
現在(2024年)、iOS SafariはWebXR AR(immersive-arモード)に対応していません。iOSユーザーへの対応にはAR.js、またはモデルビューワーのAR Quick Lookを併用する設計が必要です。
はい、WebXR APIの利用にはHTTPS(セキュアオリジン)が必須です。開発中はlocalhost(http://localhost)でも動作しますが、本番デプロイ時は必ずSSL証明書を設定してください。
A-Frameは宣言的なHTMLタグで手軽にAR/VRシーンを作れますが、複雑なインタラクションや高度な最適化には限界があります。Three.jsはコーディング量が増えますが、フルコントロールが可能です。プロトタイプにはA-Frame、本格開発にはThree.jsという使い分けが一般的です。