拡張現実: ご存じの方もいらっしゃいますか

すでに WebXR Device API を使用したことがある場合は、ほぼ問題なく使用できます。

Joe Medley
Joe Medley

WebXR Device API は Chrome 79 で昨年秋にリリースされました。前述のとおり、Chrome では API の実装が進行中です。一部の作業は終了しましたChrome 81 では、次の 2 つの新機能が導入されました。

この記事では、拡張現実について説明します。WebXR Device API をすでに使用している場合は、新たに習得すべき事項はほとんどありません。WebXR セッションの開始もほぼ同じです。フレームループの実行方法は、ほぼ同じです。違いは、拡張現実用にコンテンツを適切に表示できるようにする構成にあります。WebXR の基本コンセプトに精通していない場合は、WebXR Device API に関する以前の投稿をご覧になるか、少なくとも WebXR で取り上げられているトピックを理解する必要があります。セッションをリクエストして開始する方法と、フレームループを実行する方法を理解している必要があります。

ヒットテストについては、関連記事現実世界のビューで仮想オブジェクトを配置するをご覧ください。この記事のコードは、Immersive Web Working Group の WebXR Device API サンプルの Immersive AR Session サンプル(デモ ソース)に基づいています。

コードの詳細に入る前に、Immersive AR Session のサンプルを少なくとも 1 回使用する必要があります。Chrome 81 以降を搭載した最新の Android スマートフォンが必要です。

用途

拡張現実は、ブラウザを離れることなく AR のユースケースを実装できるため、既存または新規の多くのウェブページに有用な機能となります。たとえば、教育サイトでの学習を支援し、購入を検討しているユーザーが購入時に自宅のオブジェクトを可視化できるようにします。

2 つ目のユースケースを考えてみましょう。実際のシーンに仮想オブジェクトの実物大表現を配置する シミュレーションを想像してみてください画像を配置すると、選択したサーフェス上にそのまま配置され、実際のアイテムがそのサーフェス上にある場合のサイズで表示されます。ユーザーは画面の周りやその近くに移動したり、さらに近づいたりできるようになります。これにより、2 次元の画像よりも閲覧者はオブジェクトをより深く理解できます。

少し先になるわ。ここまで説明したことを実際に行うには AR 機能とサーフェス検出手段が必要ですこの記事では前者について説明します。WebXR Hit Test API の関連記事(上記へのリンク)では後者について説明しています。

セッションのリクエスト

セッションのリクエストは、これまで見てきたものとよく似ています。まず、xr.isSessionSupported() を呼び出して、必要なセッション タイプが現在のデバイスで使用できるかどうかを確認します。前のように 'immersive-vr' をリクエストする代わりに、'immersive-ar' をリクエストします。

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-ar');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter AR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

以前と同様に、[AR を入力] ボタンが有効になります。ユーザーがクリックすると、xr.requestSession() を呼び出して 'immersive-ar' も渡します。

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-ar')
    .then((session) => {
      xrSession = session;
      xrSession.isImmersive = true;
      xrButton.textContent = 'Exit AR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

コンビニエンス プロパティ

前のコードサンプルで 2 行をハイライト表示しました。XRSession オブジェクトには isImmersive というプロパティがあるようです。これは自分で作成した便利なプロパティであり、仕様には含まれていません。視聴者に何を表示するかを決めるときは後で使用します。このプロパティが API に含まれていないのはなぜですか?アプリでこのプロパティを別途トラッキングする必要がある可能性があるため、仕様作成者は API をクリーンな状態に保つことを決定しました。

セッションの開始

以前の記事で onSessionStarted() がどのように表示されるかを思い出してください。

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

拡張現実をレンダリングするため、いくつか追加する必要があります。背景をオフにする まず、背景が必要かどうかを判断します。これが、コンビニエンス プロパティを最初に使用する場所です。

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  if (session.isImmersive) {
    removeBackground();
  }

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });

}

参照空間

以前の記事では、参照空間についてはざっと目を通しました。今回説明するサンプルでは、このうちの 2 つを使用しているので、この省略を修正します。

参照空間は、仮想世界とユーザーの物理環境との関係を表します。仕組みは次のとおりです。

  • 仮想世界での位置を表すために使用される座標系の原点を指定する。
  • その座標系内でユーザーが移動すると想定されるかどうかを指定する。
  • その座標系に事前に設定された境界線があるかどうか。(ここに示されている例では、事前に設定された境界線を持つ座標系は使用していません)。

すべての参照空間について、X 座標は左右、Y は上下、Z は前後を表します。正の値は、それぞれ右、上、後方です。

XRFrame.getViewerPose() から返される座標は、リクエストされた参照空間タイプによって異なります。詳しくはフレームループで説明します。現時点では、拡張現実に適した参照タイプを選択する必要があります。これも私のコンビニエンスプロパティです

let refSpaceType
function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  if (session.isImmersive) {
    removeBackground();
  }

  let canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(session, gl)
  });

  refSpaceType = xrSession.isImmersive ? 'local' : 'viewer';
  xrSession.requestReferenceSpace(refSpaceType).then((refSpace) => {
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Immersive AR Session Sample を見ると、最初はシーンが静止しており、拡張現実がまったくないことがわかります。シーン内を移動するには、指でドラッグしてスワイプします。[AR を開始] をクリックすると背景が消え、デバイスを動かすことでシーン内を移動できます。モードは、異なる参照空間タイプを使用します。上のハイライト表示されたテキストは、選択方法を示しています。これには、次の参照タイプを使用します。

local - オリジンがセッション作成時の視聴者の現在地になります。つまり、エクスペリエンスの下限が必ずしも明確に定義されているわけではなく、起点の正確な位置はプラットフォームによって異なる場合があります。空間に対する事前に設定された境界はありませんが、コンテンツは回転以外の動きなしで視聴できることが想定されます。Google 独自の AR の例からわかるように、空間内でなんらかの動きが発生する可能性があります。

viewer - ページ内にインラインで表示されるコンテンツで最も頻繁に使用されます。このスペースは表示デバイスに従います。getViewerPose に渡されると、トラッキングが提供されないため、アプリが XRReferenceSpace.getOffsetReferenceSpace() で変更しない限り、常に起点でのポーズを報告します。サンプルではこれを使用して、カメラのタップベースのパンを有効にしています。

フレームループの実行

概念的には、以前の記事で説明した VR セッションで行ったことから変更はありません。参照空間のタイプを XRFrame.getViewerPose() に渡します。現在の参照空間タイプの XRViewerPose が返されます。viewer をデフォルトとして使用すると、AR または VR についてユーザーの同意がリクエストされる前に、ページにコンテンツのプレビューを表示できます。これは重要なポイントを示しています。インライン コンテンツでは没入型コンテンツと同じフレームループを使用し、維持する必要があるコードの量を削減します。

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  let xrViewerPose = xrFrame.getViewerPose(refSpaceType);
  if (xrViewerPose) {
    // Render based on the pose.
  }
}

おわりに

この一連の記事では、ウェブでの没入型コンテンツの実装の基本についてのみ説明します。Immersive Web Working Group の WebXR Device API サンプルには、さらに多くの機能とユースケースが掲載されています。また、サーフェスを検出して現実のカメラビュー内に仮想アイテムを配置するための API について説明したヒットテストの記事も公開しました。web.dev ブログでは 他の記事もご覧いただけます

写真撮影: David GrandmouginUnsplash