はじめに
この記事は、N高グループ・N中等部 Advent Calendar 2024 14日目の記事です。
はじめまして、marilと申します。去年に引き続き、今年もN高グループ・N中等部 Advent Calendarに参加させていただきます。
今回は、Meta QuestとThree.jsを使って、VRMモデルを現実へ呼び出す方法をご紹介していきます。
プロジェクト作成
今回はRemixを例に挙げて紹介していきますが、フレームワークはお好みでどうぞ。
bun create remix vrm-xr
必要なパッケージをインストールします。
bun add three @types/three @pixiv/three-vrm
シーン作成
では、実装に取り掛かっていきます。
まず、Three.jsのシーンを作成し、XR機能を有効にします。
import * as THREE from "three";
import { ARButton, OrbitControls } from "three/examples/jsm/Addons.js";
const setupScene = async () => {
//WebXRを有効化
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
document.body.appendChild(
ARButton.createButton(renderer, {
requiredFeatures: ["plane-detection"],
})
);
//シーンの作成
const scene = new THREE.Scene();
//カメラを追加
const camera = new THREE.PerspectiveCamera(
35,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0.0, 1.4, 7);
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.screenSpacePanning = true;
orbitControls.target.set(0.0, 0.0, 0.0);
orbitControls.update();
//ライトを追加
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3);
light.position.set(0.5, 1, 0.25);
scene.add(light);
function animate() {
renderer.render(scene, camera);
}
};
export default function Index() {
useEffect(() => {
setupScene();
}, []);
return <div></div>;
}
これで、XRが有効なThree.jsシーンが作成されます。
VRMモデルの読み込み
あらかじめ、public
配下にmodelsフォルダを作成し、そこに読み込みたいvrmモデルを配置しておきます。
VRMモデルを読み込む関数を実装します。
import { VRMUtils, VRMLoaderPlugin } from "@pixiv/three-vrm";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const LoadVRM = (path: string): Promise<GLTF> => {
const loader = new GLTFLoader();
loader.crossOrigin = "anonymous";
const helperRoot = new THREE.Group();
loader.register((parser) => {
return new VRMLoaderPlugin(parser, {
helperRoot: helperRoot,
autoUpdateHumanBones: true,
});
});
return new Promise((resolve, reject) => {
loader.load(
path,
(gltf: GLTF) => {
VRMUtils.removeUnnecessaryJoints(gltf.scene);
if (gltf.userData.gltfExtensions?.VRM) {
//VRM-0.xのモデルかどうかチェックする
reject(
"モデルのバージョンに互換性がありません。VRM-1.xのモデルを使用してください。"
);
}
gltf.userData.vrm.scene.traverse((obj) => {
obj.frustumCulled = false;
});
resolve(gltf);
},
(progress: { loaded: number; total: number }) =>
console.log(
"Loading model...",
100.0 * (progress.loaded / progress.total),
"%"
),
(error) => {
reject(error);
}
);
});
};
setupScene
関数に以下を追記します。
const setupScene = async () => {
//WebXRを有効化
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
renderer.xr.enabled = true;
document.body.appendChild(renderer.domElement);
document.body.appendChild(
ARButton.createButton(renderer, {
requiredFeatures: ["plane-detection"],
})
);
//シーンの作成
const scene = new THREE.Scene();
//カメラを追加
const camera = new THREE.PerspectiveCamera(
35,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0.0, 1.4, 7);
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.screenSpacePanning = true;
orbitControls.target.set(0.0, 0.0, 0.0);
orbitControls.update();
//ライトを追加
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 3);
light.position.set(0.5, 1, 0.25);
scene.add(light);
+ //VRMの読み込み
+ const gltf = await LoadVRM("モデルのパス");
+ const vrm = gltf.userData.vrm;
+ scene.add(vrm.scene);
+ vrm.scene.position.set(0, 0, 0);
+ const clock = new THREE.Clock();
function animate() {
+ const deltaTime = clock.getDelta();
+ //vrmのanimate
+ if (vrm) vrm.update(deltaTime);
renderer.render(scene, camera);
}
};
Questからアクセスしてみる
これで、VRMモデルを現実空間に呼び出す準備が整いました。
実際にMeta Quest3側からアクセスしてみましょう。
今回は、Cloudflare Tunnelを使って一時的にWebサイトを公開します。
Quick Tunnelsのセットアップ方法は、以下の記事が参考になります。
cloudflared tunnel --url localhost:5173
表示されたURLに、Meta Questからアクセスします。
「Start AR」というボタンが表示されていれば、正しくシーンが作成できています。
ボタンをタップして、確認ポップアップの「許可する」をタップします。
VRMモデルが召喚されていれば、成功です!
(初期位置ではたまにモデルが空中に浮遊したり、地面に埋まっていたりすることがあるので、その場合はvrm.scene.position.set
でy座標を調節してみてください。)
デバッグ
WebXRアプリを開発していると、エラーなどを確認するため、Quest3で動作しているWebサイトのコンソールを確認したくなることがあるかと思います。
そんなときは、Chromiumブラウザのリモートデバッグ機能を使用することで、PCからQuest上のWebサイトのコンソールを確認することができます。
デバッグの手順は、以下の記事が参考になります。
おわりに
今回は、Meta QuestとThree.jsを使って、VRMモデルを現実へ呼び出す方法をご紹介しました。
このように、Three.jsを使えば簡単にWebXRコンテンツを作成することができるので、ぜひ挑戦してみてください。