バーチャル リアリティがウェブに登場

没入型エクスペリエンス(バーチャル リアリティ、拡張現実、その間のすべて)の準備に必要な基本事項をいくつかご紹介します。

Joe Medley
Joe Medley

没入型エクスペリエンスは Chrome 79 でウェブに登場しました。WebXR Device API によりバーチャル リアリティが実現し、拡張現実のサポートは Chrome 81 で提供されます。GamePad API のアップデートにより、コントロールの高度な使用が VR に拡張されます。Firefox Reality、Oculus Browser、Edge、Magic Leap の Helio ブラウザなど、他のブラウザでもこれらの仕様が間もなくサポートされる予定です。

この記事では、没入型ウェブに関するシリーズを開始します。今回の記事では、基本的な WebXR アプリケーションの設定と、XR セッションの開始と終了について説明します。今後の記事では、フレーム ループ(WebXR エクスペリエンスの要)、拡張現実の詳細、AR セッションでサーフェスを検出する手段である WebXR Hit Test API について説明します。特に明記されていない限り、この記事と後続の記事で説明する内容は、AR と VR の両方に同様に適用されます。

没入型ウェブとは

没入型エクスペリエンスを説明する用語として拡張現実とバーチャル リアリティの 2 つを使用しますが、多くの人は、完全な現実から完全に仮想的なものまで、その間の没入度合いをスペクトルで考えています。XR の「X」は、没入型エクスペリエンスのスペクトルのあらゆるものを表す代数変数のようなもので、その考え方を反映することを目的としています。

完全な現実から完全な没入感まで、視覚体験のスペクトルを示すグラフ。
没入型エクスペリエンスのスペクトル

没入型エクスペリエンスの例としては、次のようなものがあります。

  • ゲーム
  • 360° 動画
  • 没入型環境で表示される従来の 2D(または 3D)動画
  • 住宅購入
  • 購入前に自宅で商品を見る
  • 没入型アート
  • まだ誰も思いついていないクールなもの

コンセプトと使用方法

WebXR Device API の使用に関する基本事項をいくつか説明します。ここで説明するよりも詳しく知りたい場合は、Immersive Web Working Group の WebXR サンプルまたはMDN の参考資料をご覧ください。WebXR Device API の初期バージョンに慣れている場合は、この資料全体に目を通してください。変更されています。

この記事のコードは、Immersive Web Working Group の基本的な サンプル(デモソース)に基づいていますが、 明確にするために編集されています。

WebXR 仕様の作成の一環として、ユーザーを保護するためのセキュリティ対策とプライバシー対策が強化されています。そのため、実装は特定の要件に準拠する必要があります。ウェブページまたはアプリは、視聴者から機密情報をリクエストする前に、アクティブでフォーカスされている必要があります。ウェブページまたはアプリは HTTPS で提供する必要があります。API 自体は、機能するために必要なセンサーとカメラから取得した情報を保護するように設計されています。

セッションをリクエストする

XR セッションを開始するには、ユーザー ジェスチャーが必要です。これを行うには、機能 検出を使用して XRSystemnavigator.xr 経由)をテストし、 XRSystem.isSessionSupported() を呼び出します。Chrome バージョン 79 と 80 では、 XRSystem オブジェクトは XR と呼ばれていたことに注意してください。

次の例では、 セッション タイプのバーチャル リアリティ セッションをリクエストしています。'immersive-vr'他のセッション タイプ'immersive-ar''inline' です。インライン セッションは HTML 内にコンテンツを表示するためのもので、主にティザー コンテンツに使用されます。Immersive AR Session サンプルでこれを確認できます。これについては、後の記事で説明します。

バーチャル リアリティ セッションがサポートされていることがわかったら、ユーザー ジェスチャーを取得できるボタンを有効にします。

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

ボタンを有効にしたら、クリック イベントを待ってからセッションをリクエストします。

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

このコードのオブジェクト階層に注目してください。navigator から xrXRSession インスタンスに移動します。API の初期バージョンでは、セッションをリクエストする前にスクリプトでデバイスをリクエストする必要がありました。現在、デバイスは暗黙的に取得されます。

セッションを開始する

セッションを取得したら、セッションを開始して参加する必要があります。まず、いくつかの設定を行う必要があります。セッションには onend イベント ハンドラが必要です。これにより、ユーザーが終了したときにアプリまたはウェブページをリセットできます。

シーンを描画するための <canvas> 要素も必要です。XR 互換の WebGLRenderingContext または WebGL2RenderingContextである必要があります。 描画は、これらの要素または Three.jsなどの WebGL ベースのフレームワークを使用して行われます。

描画する場所ができたので、描画するコンテンツのソースが必要です。そのため、XRWebGLLayer のインスタンスを作成します。XRSession.updateRenderState() を呼び出して、キャンバスに関連付けます。

セッションを開始したら、バーチャル リアリティで物体の位置を特定する方法が必要です。参照空間が必要です。'local-floor'参照空間は、原点が視聴者の近くにあり、y 軸が床面で 0 であり、移動しないことが想定される空間です。他の種類の参照空間もありますが、ここでは説明しきれないほど複雑なトピックです。参照空間は、画面に描画するときに必要になるため、変数に保存します。

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

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

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

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

参照空間を取得したら、XRSession.requestAnimationFrame() を呼び出します。 これは、フレーム ループで行われる仮想コンテンツの表示の開始です。

フレーム ループを実行する

フレーム ループは、ユーザー エージェントが制御する無限ループで、コンテンツが画面に繰り返し描画されます。コンテンツはフレームと呼ばれる個別のブロックで描画されます。フレームが連続することで、動きの錯覚が生じます。VR アプリケーションの場合、1 秒あたりのフレーム数は 60 ~ 144 です。Android 用の AR は 1 秒あたり 30 フレームで実行されます。コードで特定のフレーム レートを想定しないでください。

フレーム ループの基本的なプロセスは次のとおりです。

  1. XRSession.requestAnimationFrame() を呼び出します。これに応じて、ユーザー エージェントは、ユーザーが定義した XRFrameRequestCallback を呼び出します。
  2. コールバック関数内:
    1. もう一度 XRSession.requestAnimationFrame() を呼び出します。
    2. 視聴者のポーズを取得します。
    3. XRWebGLLayerWebGLFramebufferWebGLRenderingContext に渡します(「バインド」)。
    4. XRView オブジェクトを反復処理し、XRWebGLLayer から XRViewport を取得して、WebGLRenderingContext に渡します。
    5. フレームバッファに何かを描画します。

この記事の残りの部分では、ステップ 1 とステップ 2 の一部について説明します。設定と呼び出しです。XRFrameRequestCallbackステップ 2 の残りの項目については、パート II で説明します。

XRFrameRequestCallback

XRFrameRequestCallback はユーザーが定義します。DOMHighResTimeStampXRFrame インスタンスの 2 つのパラメータを受け取ります。XRFrame オブジェクトは、単一のフレームを表示にレンダリングするために必要な情報を提供します。DOMHighResTimeStamp 引数は、将来の使用を想定しています。

まず、次のアニメーション フレームをリクエストします。前述のように、フレームのタイミングは、基盤となるハードウェアに基づいてユーザー エージェントによって決定されます。最初に次のフレームをリクエストすることで、コールバック中にエラーが発生した場合でもフレーム ループが継続されます。

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

ここで、視聴者向けに何かを描画します。これについては、パート II で説明します。その前に、セッションを終了する方法について説明します。

セッションを終了する

没入型セッションは、XRSession.end() の呼び出しによる独自のコードでの終了など、いくつかの理由で終了する可能性があります。その他の原因としては、ヘッドセットの切断や、別のアプリケーションによる制御などがあります。そのため、適切に動作するアプリケーションでは end イベントをモニタリングする必要があります。イベントが発生したら、セッションと関連するレンダリング オブジェクトを破棄します。終了した没入型セッションを再開することはできません。没入型エクスペリエンスを再度開始するには、アプリで新しいセッションを開始する必要があります。

セッションを開始するで説明したように、設定時に イベント ハンドラを追加しました。onend

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

イベント ハンドラ内で、ユーザーがセッションを開始する前のアプリの状態を復元します。

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

まとめ

Web XR アプリケーションまたは AR アプリケーションを作成するために必要なすべてのことを説明したわけではありません。 コードを理解し、実験を開始するのに十分な情報を提供できたことを願っています。次の記事では、コンテンツが画面に描画されるフレーム ループについて説明します。