📝
Babylon.jsではじめるHoloLens 2 / Meta Quest対応WebXR入門(イベントレポート)
概要
2/11(土)開催の下記イベントのレポート記事兼プラスαの実装記事になります。
事前準備
- 機材の準備
- HoloLens2またはOculus Quest1,2(要OSアップデート)
- 開発用PC (Win/MacどちらもOK)
- ハンドトラッキングの有効化
- HoloLens2
- Windowsアップデートで最新版に更新
- Edgeを起動
- アドレスバーに edge://flags と入力して検索
- webxrで検索
- WebXR IncubationsをEnabledに変更
- OculusQuest
- 最新版にアップデート
- ハンドトラッキング機能をON
(参考: https://apicodes.hatenablog.com/entry/oculus-handtracking ) - Webブラウザを起動
- アドレスバーに chrome://flags と入力して検索
- handで検索
- WebXR experiences with hand and joints trackingをEnabledに変更
- HoloLens2
- Glitchのアカウント準備
- ハンズオン資料のダウンロード
開発
開発環境は、Web上でコーディングから公開までできるGlitchを使用
⇒下記のような画面が立ち上がる
詳細はこの記事では割愛しますが、スライドでは各部の解説までされています
いきなり完成品で申し訳ないですが、最終的な成果物はこちら
<html>
<head>
<!--babylon.jsの読み込み-->
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
<!--実際の処理の実装-->
<script type="text/javascript">
let canvas; //canvas要素 (描画領域)
let engine; //Babylon.jsによる描画機能
let scene; //仮想3D空間
//ページの読み込み終了後に各種初期化を行う
window.onload = function() {
//描画領域(canvas要素)をHTMLから取得
canvas = document.getElementById("renderCanvas");
//Babylon.jsを使ってcanvasに描画する準備 (引数:描画先,アンチエイリアス)
engine = new BABYLON.Engine(canvas, true);
//カメラやライトの設定を行ったscene(3D空間)を作成
createScene();
//描画オブジェクトの作成
addObjects();
//XRモードの初期化
initializeXR();
//毎フレーム描画を更新
engine.runRenderLoop(function () {
if (scene && scene.activeCamera) {
scene.render();
}
});
}
//3D空間の初期化
function createScene() {
//3D空間を作成
scene = new BABYLON.Scene(engine);
//背景色を設定
scene.clearColor = new BABYLON.Color3.Black();
//Lightを設定 (引数:名前,反射の方向,追加先)
let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, -0.5));
//カメラを作成(引数:名前, alpha, beta, 注視点からの距離, 注視点,追加先)
let camera = new BABYLON.ArcRotateCamera("camera", -Math.PI/2,Math.PI/2, 3, new BABYLON.Vector3(0, 0, 0));
//マウスやキーボードによるカメラ操作を可能にする
camera.attachControl(canvas, true);
}
//WebXRの初期化
async function initializeXR(){
let xr = await scene.createDefaultXRExperienceAsync({/*ここでオプションも設定可能*/});
//XRモード利用可能か不可かを確認
if (!xr.baseExperience) {}
else {
//利用可能な場合はハンドトラッキングをオンにする
xr.baseExperience.featuresManager.enableFeature(BABYLON.WebXRFeatureName.HAND_TRACKING, "latest", {
xrInput: xr.input
});
}
}
//表示オブジェクトの初期化
function addObjects(){
//地面を作成(原点の位置確認用。あとで削除してOK)
let ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 1, height: 1});
//箱状のオブジェクト作成(30cm)
let box = BABYLON.MeshBuilder.CreateBox("box", {width: 0.3, height: 0.3, depth: 0.3});
box.position.x = 0;
box.position.y = 1;
//箱の色をランダムに設定
let boxMaterial = new BABYLON.StandardMaterial("material");
boxMaterial.diffuseColor = BABYLON.Color3.Random();
box.material = boxMaterial;
//8面体を作成
let octa = BABYLON.MeshBuilder.CreatePolyhedron("octa", {type:1,size: 0.15});
octa.position.x=0.5;
octa.position.y=1;
//boxに手で掴んで移動できる属性を追加
let dragBehavior = new BABYLON.SixDofDragBehavior();
//片手での操作のみ受け付ける(両手でのスケールでの挙動がおかしいため)
dragBehavior.allowMultiPointer=false;
//離れた位置からポインターで操作する場合は位置のみ追従
dragBehavior.rotateWithMotionController=false;
//上記設定をboxに適用
box.addBehavior(dragBehavior);
//SceneLoaderを使って3Dモデルを読み込む
BABYLON.SceneLoader.LoadAssetContainer(
"https://cdn.glitch.global/d0ecf79e-59af-4280-90df-a28f3efaad3e/figure.glb?v=1675334298545", //3Dモデルが置かれたフォルダ or 3DモデルのURL
"", //3Dモデルのファイル名。上記でモデルのURLを指定した場合は空でOK
scene, //オブジェクトを追加する先のScene
function (container) {
//Babylon.jsでは0番目のメッシュはただのroot。1番目にモデルの実体。
let glbMesh = container.meshes[1];
//スケールを10倍
glbMesh.scaling=new BABYLON.Vector3(10,10,10);
//Y軸(=鉛直方向の軸)を中心に180度(=πラジアン)回転
glbMesh.rotation =new BABYLON.Vector3(0, Math.PI, 0);
//読み込んだオブジェクト用にマニピュレーションの挙動を作成
let dragBehavior2 = new BABYLON.SixDofDragBehavior();
dragBehavior2.allowMultiPointer=false;
dragBehavior2.rotateWithMotionController=false;
glbMesh.addBehavior(dragBehavior2);
//scene(3D空間)にオブジェクトを追加
scene.addMesh(glbMesh);
}
);
}
</script>
</head>
<body>
<!--描画する領域-->
<canvas id="renderCanvas" style="width: 100%; height: 100%;"></canvas>
</body>
</html>
+α実装
モデル変更
モデルはAssets > Upload An Assetを選択し、アップロードできます
アップロードしたモデルを選択すると、URLが作られているのでコピー
85行目付近のモデルURLをコピーしたものに差し替え
glbMeshのpositionなどを調整して完成
パススルー対応
Questでパススルーを使うには、45行目付近のscene.createDefaultXRExperienceAsync
のオプションを下記のように設定する
let xr = await scene.createDefaultXRExperienceAsync(
{
uiOptions: {
sessionMode: 'immersive-ar'
}
});
このとき、モデルがカメラ位置の所に来てしまうので、58行目付近のXRモード利用可能のときの処理に下記を追記
//カメラの初期位置を調整
xr.baseExperience.sessionManager.onXRFrameObservable.addOnce(() => {
xr.baseExperience.camera.position = new BABYLON.Vector3(0,scene.activeCamera.position.y,-2);
});
宣伝
参考
Discussion