WebXR Device APIの登場

UI開発者 加藤

この記事はミツエーリンクスアドベントカレンダー2019 - Qiitaの13日目の記事です。

「VRの普及元年」といわれた2016年からはや3年が経過しました。Oculus RiftやHTC Vive、PlayStation VRなどを代表とするVRデバイスが数多く販売され、ハイエンドなデバイスも比較的安価で購入できる時代になりましたね。これまでは主に研究機関やBtoB型ビジネスで活用されていたVR技術が、より消費者に近い存在になってきていると感じます。

WebにおけるXR(VR、AR、MRなどの総称の意)も同時期からWebVR APIという名前でAPIの仕様策定が進んでいました。当時はスマートフォンの画面を2分割して、カードボードや専用のハーネスにセットし手軽なVR体験ができることで話題になりました。(あのとき持っていたGear VRはどこへ...)

そんな中、先日リリースされたGoogle Chromeのバージョン79でWebXR Device APIがとうとう実装されました。今回はこのWebXR Device APIを簡単に見ていきたいと思います。

WebXR Device APIとは

WebXR Device APIは先述したWebVRの上位互換といえるAPIです。WebVRはその名の通り「VR」のみをサポートするために設計されていましたが、WebXR Device APIはVRだけでなくARなどもサポートできるように各種センサーやXRデバイスとやりとりするAPIを提供することを目的としています。あくまでデバイスとブラウザ間のインターフェースを定義するだけであり、XRコンテンツ自体を作るためのAPIではありません。

「XRデバイス」というと、ヘッドマウントディスプレイのような本格的なデバイスを想像されるかもしれませんがWebXR Device APIが対象とするデバイスにはスマートフォンも含まれています。たいていのスマートフォンはカメラが搭載されているため、カメラで撮影した映像を画面に表示しながらコンテンツをオーバーレイ表示するいわゆるARコンテンツを手軽に表現できます。例えば、最近のGoogle検索には特定の動物を検索すると動物の3DモデルをARで表示できる機能が備わっています。

サメの3Dモデルを表示している例

WebXR Device APIを使えばこのようなARコンテンツをWeb技術のみで提供できるようになります。

XRアプリケーションの基本的な処理の流れは以下のとおりです。

  1. XRオブジェクトを通してユーザーエージェントがXRをサポートしているかどうかをチェックする
  2. サポートされている場合、XRモードを開始するためのトリガーとなるボタンを表示する
  3. ボタンが押下されたら、XRSessionオブジェクトの取得をリクエストする
  4. 取得したセッションを通してXRデバイスにコンテンツを描画する

その後はユーザー、もしくはユーザーエージェントがセッションを終了するまで描画を繰り返します。細かく見ていくとさまざまなオブジェクトが登場しますが、ここでポイントとなるのは「XRオブジェクト」と「XRSessionオブジェクト」の2つです。

XRオブジェクト

XRオブジェクトはWebXR機能のエントリポイントとなるオブジェクトでnavigator.xrから取得できます。ユーザーエージェントが対応しているモードの判定や後述するXRSessionオブジェクトの取得など、基本的な機能を持っています。

現在の仕様に掲載されているモードは以下の3つです。

  • inline: HTMLドキュメント内の要素として出力されるモードです。
  • immersive-vr: 最終的な出力のみXRデバイスに表示されるモードです。
  • immersive-ar: 最終的な出力とユーザーの環境(カメラからの映像など)が統合され、XRデバイスに表示されるモードです。

inlineモードでは単一のビューで出力されるのに対して、immersive-vrimmersive-arモードでは画面が自動的に2分割されます。デバイスが各モードに対応しているかどうかはXRオブジェクトが持っているisSessionSupportedメソッドを使用します。

const isSupportVR = await navigator.xr.isSessionSupported( 'immersive-vr' );

XRSessionオブジェクト

XRデバイスに描画したり、ユーザーの姿勢(頭の傾き、スマートフォンの回転角など)を得るなどのブラウザとXRデバイスの連携はXRSessionオブジェクトを通して行われます。XRSessionはXRオブジェクトが持つrequestSessionメソッドを実行すると取得できます。

const vrSession = await navigator.xr.requestSession( "immersive-vr" );

requestSessionを実行するとデバイス側にプロンプトが表示されます。以下はAndroid Chromeでの表示です。

「VRを許可して開始」を選択すると画面がVRモードになります。あとはXRSessionオブジェクトを通じて、レンダリングするフレームをデバイスに渡します。ライブラリなしで実装しようとすると大変ですが、3Dコンテンツをお手軽に実装できるthree.jsを使えば、WebXRに対応した描画処理もとても簡単に実装できます。例えばスカイボックスコンテンツを作る場合は以下のように書くことができます。

import * as THREE from './js/libs/three.module.js';
import { VRButton } from './js/libs/VRButton.js';

let renderer;
let scene;
let camera;

function init() {
    let urls = [
        '/img/room/positive_x.jpg', '/img/room/negative_x.jpg',
        '/img/room/positive_y.jpg', '/img/room/negative_y.jpg',
        '/img/room/positive_z.jpg', '/img/room/negative_z.jpg'
    ];

    renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( parent.offsetWidth, parent.offsetWidth * 0.5625 );

    // three.jsのXRモードを有効にする
    renderer.xr.enabled = true;
    document.body.appendChild( renderer.domElement );

    // 「VRで見る」ボタンを設置
    document.body.appendChild( VRButton.createButton( renderer ) );

    scene = new THREE.Scene();
    scene.background = new THREE.CubeTextureLoader().load( urls );
    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 20 );
    scene.add( camera );
    animate();
}

function animate() {
    renderer.setAnimationLoop( render );
}

function render() {
    renderer.render( scene, camera );
}

init();

実際にはthree.jsの内部でさまざまな処理が行われていますが、たった40行程度で簡単なVRコンテンツが作れてしまいます!実行結果は以下のようになります。

冒頭で書いた通り、すでにさまざまなXRデバイスが販売されています。デバイスの種類が多いことは消費者が自分の要望に合ったデバイスを選ぶことができる一方、3DoFや6DoFなど備わっている機能や性能もデバイスごとに違うことがあります。そのためすべてのデバイスでうまくXRコンテンツを動かすには、デバイスがサポートしている機能を逐一確認しながら処理を分岐させていく必要があります。

WebXR Device APIはもちろん、XRデバイス自体もまだ過渡期ではありますが、Web上でXRコンテンツが表現できるようになったことは大きな変化だと思います。WebXR Device APIの登場によって今後のWebコンテンツがどう変わっていくのか、楽しみですね。