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

バーチャル リアリティや拡張現実など、さまざまな没入型体験に備えるための基本をいくつかご紹介します。

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 エクスペリエンスの主軸)、拡張現実の詳細、WebXR Hit Test API(AR セッションでサーフェスを検出する手段)について説明します。特に明記されていない限り、この記事と後続の記事で扱う内容は、AR と VR の両方に等しく適用されます。

没入型ウェブとは

拡張現実(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 セッションに入るには、ユーザー操作が必要です。これを取得するには、機能検出を使用して(navigator.xr を介して)XRSystem をテストし、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 である必要があります。描画はすべて、これらのライブラリまたは WebGL ベースのフレームワーク(Three.js など)を使用して行われます。

描画する場所が用意できたので、それを描画するコンテンツのソースが必要です。そのために、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 は 30 フレーム/秒で動作します。コードで特定のフレームレートを想定しないでください。

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

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

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

XRFrameRequestCallback

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

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

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

次は、視聴者のために何かを描きます。これがパート 2 の ディスカッションですその前に、セッションを終了する方法をご説明します。

セッションを終了する

没入型セッションは、いくつかの理由で終了することがあります。たとえば、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 アプリケーションの作成に必要なものをすべて説明できていません。コードの理解が深まり 実験を始めるのに 十分な知識が十分あれば幸いです次の記事では コンテンツが画面に描画される フレームループについて説明します

写真撮影: JESHOOTS.COMUnsplash