比留間 和也

VR成功の鍵はWebVRにあり!? ── HTML5 Conference 2016セッションレポート

セッション内容を講演者自らが解説するという「HTML5 Conference 2016特集」の第三弾。今回のテーマは「Webのグラフィックス後編: WebGL2、そしてWebVR」。
すでに策定が始まっている次期バージョンWebGL2.0のお話や、WebでVRを実現する「WebVR API」を用いてVRコンテンツの実装の仕方を解説します。

VRとは?

今年、2016年はVR元年と言われ、様々なVRデバイス、VR関連ガジェット、VRコンテンツが世に生み出されています。 しかし、VR発祥は意外と古く、遡ること1960年代にVRの基礎となる理論、デバイスが発表されています。

ただ当時は個人で手が出るものではなく、体験自体はデパートのアトラクションとして登場するなど、体験は限定的でした。

352930-sensorama-1962
参考

時を戻して2016年。世界が動き出します。
2016年6月時点のGoogle検索トレンドでは、検索回数が飛躍的に伸びているのが見てとれます。

unnamed

きっとこれを読まれている方も、周りで「VR」というワードを聞くことが増えてきたのではないでしょうか。そしてこの波に乗るように、VRについてもWebでの体験を可能にする技術が公開されています。

WebVRは体験の話ではない

WebでのVR技術、それが「WebVR」です。
取りざたされているVRを手軽にWebで体験できるもの。それが「WebVR」。

…ではなく。
あくまでWebVRはイチ仕様に過ぎません。
つまり、WebVRに対応したからといって、即座にWeb上でVRコンテンツを提供できる、という類のものではないということです。

WebVRはAPIの仕様

誤解を恐れずに言えば、WebVRはセンサーからの情報を扱うためだけのAPIです。
要は、HMD(ヘッドマウントディスプレイ)からの位置、回転、視野情報など様々な、ハードウェアの情報を取り扱うAPIということです。もっと言ってしまえば、モバイルで利用しているジャイロセンサーとなんら変わることはない、ということです。

事実、WebGLの仕様と比べると格段に少ない内容の仕様となっています。(仕様はこちら

VRコンテンツの構築

Webで手軽に体験できるVRコンテンツ、と書きましたが提供する側が同じく手軽であるとは限りません。
(とはいえ、その他のネイティブなVRコンテンツと比較すると格段に手軽だと思いますが)

WebVRはただのAPIだと書きました。
つまり、VRコンテンツ自体は別のAPI、具体的にはWebGLを利用して3Dコンテンツを制作する必要があります。事実、VRコンテンツの制作について既存の3Dコンテンツの制作と違いはほとんどありません。

WebGLコンテンツでは通常、requestAnimationFrameなどを利用して、一定時間置きに画面を更新しアニメーションやインタラクションを実現します。ジャイロセンサーを使ったコンテンツの制作を行ったことがある方であれば、どういったコンテンツが制作できるのかのイメージがわくでしょう。

そして上でも書いたように、ジャイロセンサーで行っていたような処理をWebVR APIに替えて画面を更新してやればいいのです。

ただし、(当然ではありますが)通常のWebGLコンテンツとWebVRコンテンツでは決定的に違うところがあります。それは「VR体験を作り上げる必要がある」という点です。

具体例を上げましょう。
今までの3Dコンテンツはカメラの位置は製作者側で制御可能でした。
ということはつまり、都合の悪い、カメラの後ろ側を映さないようにカメラを制御することができた、ということです。 しかし、VRコンテンツはそのカメラの操作はユーザーの視点という形で使われるため、当然、その後ろ側を見られる可能性があります。
(というより、ほとんどの場合、ユーザーはあたりを見渡すでしょう)

このように、裏側が見られてしまうということは、悪く言えば手抜き、よく言えば無駄を省いた部分までもしっかりと作り込まないとならないということを意味しています。

基本的なセットアップ方法

さて、それではざっくりとですが、WebVR APIを使ったセットアップのコードを紹介しましょう。
本コードはこちらのサイトのサンプルを引用させていただいています。

▼ HMDハードウェアの参照を取得する

navigator.getVRDisplay().then(function (displays) {
    if (!displays.length) {
        return;
    }

    vrDisplay = displays.length[0];
}).catch(function (err) {
    console.error('Could not get VRDisplay', err.stack);
};


▼ 描画対象として必要なサイズを取得する

var eyeParameter = vrDisplay.getEyeParameters('left');
var width = eyeParameter.renderWidth;
var height = eyeParameter.renderHeight;


▼ WebGLのCanvasおよびVRモード移行のための処理を記述

var webglCanvas = document.querySelector('#webglcanvas');
var enterVRBtn = document.querySelector('#entervr');

enterVRBtn.addEventListener('click', function () {
    vrDisplay.requestPresent({source:webglCanvas});
}, false);

vrDisplay.exitPresent();


▼ 画面のアニメーションループを処理する

var id = vrDisplay.requestAnimationFrame(onAnimationFrame);

function onAnimationFrame() {
    id = vrDisplay.requestAnimationFrame(onAnimationFrame);
}

vrDisplay.cancelRequestAnimationFrame(id);


▼ HMDのセンサーからの値を取り出す

var pose = vrDisplay.getPose();

var orientation = pose.orientation;

var position = pose.position;


▼ ハードウェアに設定された個々の設定を読み取る(瞳孔間距離など)

var eyeParameters = vrDisplay.getEyeParameter('left');

var eyeOffset = eyeParameters.offset;

var eyeMatrix = makeProjectionMatrix(vrDisplay, eyeParameters);


▼ 取得した情報から、プロジェクション行列を生成する

function fieldOfViewToProjectionMatrix (fov, zNear, zFar) {
    var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
    var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
    var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
    var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
    var xScale = 2.0 / (leftTan + rightTan);
    var yScale = 2.0 / (upTan + downTan);

    var out = new Float32Array(16);
    out[0] = xScale;
    out[1] = 0.0;
    out[2] = 0.0;
    out[3] = 0.0;
    out[4] = 0.0;
    out[5] = yScale;
    out[6] = 0.0;
    out[7] = 0.0;
    out[8] = -((leftTan - rightTan) * xScale * 0.5);
    out[9] = ((upTan - downTan) * yScale * 0.5);
    out[10] = -(zNear + zFar) / (zFar - zNear);
    out[11] = -1.0;
    out[12] = 0.0;
    out[13] = 0.0;
    out[14] = -(2.0 * zFar * zNear) / (zFar - zNear);
    out[15] = 0.0;

    return out;
}

Three.jsを使えばお手軽

WebGLといえばThree.js、というくらいデファクトスタンダードなライブラリとなったThree.js。
実はThree.jsのリポジトリにはWebVRに対応するためのプラグインがすでに存在しています。

それは VRControl.js と VREffect.js の2種類です。
これはどちらもThree.jsでVRを実現するのを手助けしてくれるプラグインです。
VRControl がHMDのセンサーの処理を、 VREffect.js がフルスクリーンモードへの移行や、VRモードの表示を手助けしてくれます。

基本的に、Three.jsを使った3Dコンテンツ制作の方法はVR化すると言っても大きな違いはありません。
その証拠に、VR化するためのコード断片は以下のようにとても短いものとなります。

var controls = new THREE.VRControls(camera);
var effect = new THREE.VREffect(renderer);

// clickイベントなどのユーザ操作のタイミングで実行される関数
function toVRMode() {
    effect.requestPresent();
}

対応ブラウザ

対応ブラウザは、執筆時点(2016/09/28)ではまだ限定的にしか存在していません。
安定版で動作するものは今のところないのが現状です。

対応状況は以下のサイトから確認することができます。
Is WebVR Ready?

VR成功の鍵を握るのはWebVR

個人的な見解ですが、VR成功の鍵をにぎるのはWebVRにあると思っています。
その理由はいくつかあります。

一つ目が、プラットフォーム(Oculus Rift、HTC Viveなど)に依存しないこと。
つまり今までのWebアプリと同様に、モバイル、PCなどのプラットフォームに依存しないコンテンツ展開ができることです。

二つ目に、インストールが不要なこと。ネイティブアプリにしてしまうとどうしてもこの「インストール」という手順が必要になってしまいます。しかし、WebVRであればWebサイトに訪れたユーザが、VRモードの開始ボタンを押すだけでVR体験をすることが可能になります。

そして最後の三つ目として、「ちょっとだけVR」が使えること。
例えばECサイトの商品をVRで見てみる、例えば不動産サイトの部屋の感じをVRで体験してみる、などなど、VRが活用できればユーザの利便性が上がることはたくさんあります。

しかし、例えばこれらを、アプリをインストールしたのちにしか行えないとしたら大部分の人はそれを倦厭するでしょう。

またコンテンツ制作側からしても、そんなちょっとしたVRアプリだけをプラットフォームに載せて配信する、というハードルの高さも出てくるでしょう。

こうしたように、今までの「Webならではの良さ」がそのままVRにも当てはめることができると考えています。そしてこれが結局、VRとユーザの接点となり、より多くの人にVRとはなにか、VRでどんなことができるかを広める機会になると考えています。

まとめ

まとめると、

  • WebVRはAPIの名称
  • WebVR APIがやってくれるのはセンサーの値を取るなどの最低限の処理のみ
  • Three.jsを使えば手軽にVRコンテンツの制作が可能
  • とはいえまだサポートブラウザが(ほぼ)ない
  • しかし、Webでの活用はまだまだ(いい意味で)未知数

ということです。
詳細についてはカンファレンスで使用したスライドがアップされているので、そちらを参照ください。

当日の動画は下記で公開されていますので、こちらも参照してください。(編集部注:動画は3:26:10あたりから比留間さんの講演となります)

de:code 2017
Powered byNTT Communications

tag list

アクセシビリティ イベント エンタープライズ デザイン ハイブリッド パフォーマンス ブラウザ プログラミング マークアップ モバイル 海外 高速化 Angular2 AngularJS Canvas Chrome Cordova CSS de:code ECMAScript Edge Firefox Google Google I/O 2014 HTML5 Conference 2013 html5j IoT JavaScript Microsoft Node.js PhoneGap Polymer React Safari SkyWay TypeScript UI UX W3C W3C仕様 Webアプリ Web Components WebGL WebRTC WebSocket