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

仮想現実、拡張現実、その他の没入型体験を体験する前に知っておくべき基本事項をご紹介します。

Joe Medley
Joe Medley

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

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

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

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

没入型の体験の例:

  • ゲーム
  • 360° 動画
  • 臨場感のある環境に表示される従来型の 2D(または 3D)動画
  • 住宅購入
  • 購入前に商品を自宅で確認する
  • 没入型アート
  • 誰も思いつかないようなクールなもの

コンセプトと使用方法

ここでは、WebXR Device API の基本的な使用方法について説明します。ここまでで説明した内容よりも詳しく知りたい場合は、Immersive Web ワーキング グループの WebXR サンプルまたは MDN の参照資料をご覧ください。WebXR Device API の初期バージョンに精通している場合は、これらの資料をすべて確認してください。変更が加えられています。

この記事のコードのベースは、Immersive Web ワーキング グループのベーシック サンプル(デモソース)ですが、わかりやすくシンプルにするために編集されています。

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

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

XR セッションに入るには、ユーザーの操作が必要です。これを実現するには、特徴検出を使用して(navigator.xr を介して)XRSystem をテストし、XRSystem.isSessionSupported() を呼び出します。Chrome バージョン 79 と 80 では、XRSystem オブジェクトは XR と呼ばれていました。

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

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

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 から xr に移動し、XRSession インスタンスになります。以前のバージョンの 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 アプリケーションの場合、フレームレートは 60 ~ 144 の範囲で指定できます。Android 向け AR は 30 フレーム/秒で動作します。コードで特定のフレームレートを前提としない。

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

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

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

XRFrameRequestCallback

XRFrameRequestCallback はユーザーが定義します。DOMHighResTimeStampXRFrame インスタンスの 2 つのパラメータを取ります。XRFrame オブジェクトは、ディスプレイに 1 つのフレームをレンダリングするために必要な情報を提供します。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';
}

まとめ

ウェブ XR または AR アプリケーションの作成に必要なすべての内容を説明したわけではありません。ここまでで、コードを理解し、テストを開始するのに十分な情報を提供できたと思います。次のセクションでは、コンテンツが画面に描画されるフレームループについて説明します。

写真提供: JESHOOTS.COMUnsplash