three.jsでWebXR - Hit-Test のソースを確認する

すぎどん
2021-03-31
すぎどん
2021-03-31

three.jsのWebXR Exampleソース

前回、three.jsのソースをWebXR(VR)に対応させる方法を記載しました。
https://dev.startialab.blog/WebVR/a128

今回はそれに加えて、WebARの機能であるHit-Testを使うための設定箇所について説明します。

題材とするのは、three.js Examplesにある「webxr_ar_hittest.html」で、
WebXR対応およびHit-Testに必要な設定箇所を解説いたします。
https://github.com/mrdoob/three.js/blob/dev/examples/webxr_ar_hittest.html
(2021/03/29時点のソースを元にしています)

WebXRの設定

WebARの設定を追加します。前回がVRButton.jsに対して今回はARButton.jsです。
違いはARButton.jsの設置時の設定だけで、他は同じになります。

ARButton.jsライブラリの取得

ソースコード18行目
ARを許可するボタンの設置と、WebXR設定を行ってくれる「ARButton.js」を読み込みます。

import { ARButton } from './jsm/webxr/ARButton.js';

RendererのWebXR設定

ソースコード50行目
rendererのxrプロパティを有効化します。

renderer.xr.enabled = true;

ARButtonの設置

ソースコード55行目
上記で読み込んだARButtonライブラリを設置します。

VRButtonと違うのは、第二引数にhit-testを設定しています。

document.body.appendChild( ARButton.createButton( renderer, { requiredFeatures: [ 'hit-test' ] } ) );

アニメーションループ実装の変更

ソースコード106行目
アニメーションループの実装を行います。

通常Three.jsでは「window.requestAnimationFrame」を利用してループ処理を実装します。
WebXRではsetAnimationLoopでフレームごとの処理を設定します。

ここまでは、VRButtonでVR対応した際とほとんど同じです。

renderer.setAnimationLoop( render );

ループ内の実装

ここからは、hit-testを使って床面や側面を検知した結果をレチクルに反映する機能実装となります。
setAminationLoopで設定した関数である「render」を、1フレーム毎に実行していきます。
このrender関数のcallbackとして2つの値が渡されます。

 ・timestamp:前フレームから今フレームまでに経過した差分時間msec
 ・frame:session情報など、1フレーム内で様々な処理を行うために必要な情報を取得することができます。

ここからはWebXR Device APIの考え方の理解がいくつか必要となってきます。
簡単に説明しますが、詳し句知りたい方は以下のURLを参考にされてください。
https://developer.mozilla.org/ja/docs/Web/API/WebXR_Device_API

hitTestSourceの取得

ソースコード114〜138行目
session.requestReferenceSpace( 'viewer' ) で取得した ReferenceSpace情報を元に
session.requestHitTestSource( { space: referenceSpace } ) で hitTestSourceを取得しています。

取得したhitTestSourceはsessionが完了するまで保持します。

ReferenceSpaceがよくわからないかと思います。
どのような空間でAR表示する想定かを表しています。
詳細については以下参照ください
https://developer.mozilla.org/ja/docs/Web/API/XRReferenceSpace

session.requestReferenceSpace( 'viewer' ).then( function ( referenceSpace ) {

session.requestHitTestSource( { space: referenceSpace } ).then( function ( source ) {

hitTestSource = source;

} );

} );

hitTestResultsの取得

ソースコード140〜157行目
frame.getHitTestResults( hitTestSource ) でhitTest結果を取得しています。
hit.getPose( referenceSpace ).transform.matrix で位置、回転、スケール情報を格納した行列を取得します。
フレーム毎にレチクルオブジェクトへ反映することで、水平面や垂直面に沿うような動きを実現しています。

const hitTestResults = frame.getHitTestResults( hitTestSource );

if ( hitTestResults.length ) {

const hit = hitTestResults[ 0 ];

reticle.visible = true;
reticle.matrix.fromArray( hit.getPose( referenceSpace ).transform.matrix );

} else {

reticle.visible = false;

}

まとめ

hit-testを使って簡単に水平面、垂直面を取れるようになりました。
思っていたよりも実装量が少なくて拍子抜けしたかもしれません。

水平面、垂直面を取れるようになるとAR表現の幅がグッと広がると思います。
Three.jsには他にもWebXRのExamplesはありますので、参考にされると良いかと思います。
https://threejs.org/examples/