比留間 和也

JSだけでVRできる!『WebVR』ことはじめ

今年はVR元年と呼ばれています。
実は過去にも何度かVR元年と呼ばれ、VRが来る、と言われていた年があります。
ですが、今年はいよいよそれが本格的になりそうな状況になってきました。

そこで今回は、「今からWebVRに備えよう!」ということで、WebVRとはなにか、それを利用して何ができるのか、利用シーンはどうか、といったことに焦点を当てたいと思います。

VR元年

本格的になりそうなのはなぜか。まずひとつ挙げられるのはOculus Rift(詳細は後述)に代表される、いくつかのヘッドマウントディスプレイ(以下、HMD)が比較的安価に家庭で利用できるようになったことです。
今年に発売される予定のものだけでも、Oculus RiftHTC VivePlayStation VRFOVE(開発キット版)など様々なHMDが市場に登場する予定になっています。
またこれらが注目される理由として、現在のPCのハードウェア性能が、HMDの必要としている要件を満たしてきた、という点も大きいでしょう。

しかしながら、Oculus Riftに関して言えば 2,160 x 1,200 という高解像度の画面を90FPS、つまり1秒間に90回もレンダリングをしなければなりません。
これは最近のPCであっても、ミドルハイクラス〜ハイエンドクラスのGPUが搭載されているPCが必要であり、安価と言っても「今までに比べて」という側面があることは否めません。

とはいえ、一般ユーザーが手にできるPCでそれを実現できる、というのはやはり大きなポイントでしょう。
現在に至るまでVRは、研究所や政府機関、あるいは財力のある企業に限定されていました。
Oculus Riftの登場により、その敷居が格段に下がったのが今年、というわけです。

例えば今までは大きなアミューズメントパークでしか体験できなかったようなことが家庭でもできる、と考えるとその凄さが実感できるでしょう?

Oculus Rift

oculus-image

さて、そんな話題のOculus Riftとはなにか。
VRの火付け役とも言えるOculus Riftは、ヘッドマウントディスプレイ、つまり頭にかぶるようにして利用するディスプレイです。
今までのHMDとの大きな違いは、その視野の広さとヘッドトラッキング/ポジショントラッキング機能が搭載されたことです。

これらがなにをもたらしてくれるか。それは、圧倒的な没入感です。
視野の広さにより、目に映るVRの世界はとても広く、「本当にそこにいるように」感じることができます。
さらに、ヘッドトラッキング/ポジショントラッキングの機能により、右を向いたり、左を向いたり、当然上下も見ることができ、360度の世界を「見渡す」ことが可能となります。
これらの機能によって圧倒的な没入感が生まれ、3D空間に入り込んでしまったような感覚を味わうことができるのです。

とはいえ、VRを説明する上で一番むずかしいのは、この没入感はHMDの機能によって「脳に錯覚」させている点です。
つまりVRを体験したことがない人に言葉や動画だけではすべてを説明することができません。
百聞は一見にしかず、という言葉が本当にぴったりです。

しかし逆を返せば、一度でも体験してもらえさえすれば、そのすごさと魅力を伝えることができるはずです。

VRをWebに持ち込む意味

そんな中、VRの波はWebの世界にもやって来ました。それが「WebVR」という仕様です。
WebVRが何かと言うと、前述したOculus Riftに代表されるHMDをWeb上で動かそう、というものです。
そうです。つまりOculus RiftをJavaScriptで動かすことができるのです。

WebVRの仕様や使い方についてはもう少しあとでお話しましょう。
まずはVRをWebの世界に持ち込むことの意味を、筆者の考えを元に説明したいと思います。

URLだけでコンテンツをシェアすることができる

VRに限らず、Webのいいところはアプリなどのインストールなしに、ブラウザでアクセスするだけでコンテンツが体験・利用できるところです。
これはVRについても同様のことが言えます。
WebVRを利用したサイトとしては、MozVRという、Mozillaの運営するサイトがWebVRを用いて実装されています。
(Oculus Riftをお持ちの方は、アクセスしてみるとすぐにでも見ることができます。このように、URLをシェアするだけで体験してもらえるのも大きなポイントのひとつですね)

またWebということはデバイスを限定しない、という側面もあります。
まぁ実際のところハードウェア性能だったり画面解像度だったり、理想と現実で違う部分もありますが、環境を限定しないようにしていく、という視点は大事なポイントでしょう。
つまりなにが言いたいかと言うと、WebにVRを持ち込むことでひとつのVRコンテンツをOculus Rift向けとスマートフォン向けに提供できる、ということです。

実際に、筆者が勤める面白法人カヤックのVR部のサイトはWebGLで実装しており、Oculus Riftが接続されたPCかスマートフォンで閲覧するとVRモードで見れるようになっています。
WebGLに対応したものであれば、お手持ちのスマートフォンで見ることができるのでぜひ見てみてください。

WebVRをどうコンテンツに活用するか

では実際に、VRをどうWebコンテンツにしていったらいいのでしょうか。
正直なところを書いてしまうと、いかようにでもできる、というのが現時点での感想です。
VRは3D空間に入り込んだように見せることができるため、本当に様々な分野に活用されています。
ゲームはもちろんのこと、介護や医療などにも応用されています。

また最近では、VR空間上でコミュニケーションできる「BigScreen」というソーシャルVRアプリが発表されました。
FacebookもソーシャルとVRについて注目しています。
個人的には、Skypeなどで行っている動画チャットによる会議なども、VRにすることでより自然な形で、オンライン上のやりとりができると考えています。

VRミーティングみたいなものはWebと相性のいい例です。なにせ、URLをシェアしてそこにアクセスするだけでミーティングが始められるわけですから。

以上のように、VRは様々な活用方法があり、あとはアイデア次第でいかようにもできる、というポテンシャルを秘めていると考えています。

今からでもできる! スマホVR

さて、ではいよいよWebVRの仕様や使い方について解説していきます。

実のところ、スマホでのVRはWebVRはまったく関係ありません。
というより、スマホにはVRコンテンツを表示する上で必要な機能がすでに備わっています。
スマホには

  • 高解像度の画面
  • ジャイロセンサーによる頭の向きのトラッキング
  • VRコンテンツを表示するための高性能なCPU/GPU

つまり、制作者側が準備さえすれば、すでにVRを体験する土台は整っている、というわけです。
(実際のところはやはりそれなりのハードウェア性能が求められるので、iPhone6などの最近の端末が必要になることは否めませんが)

ある程度ユーザー環境を限定してしまうものの、Oculus RiftなどのHMDデバイスを持っていないユーザーに対して、それも圧倒的多数のユーザーに対してVRコンテンツを届けられるのは事実です。
ただ一点だけ、解決しなければならない問題があります。
それは、例えVRコンテンツを表示する準備ができたとしても、それを立体視する道具がなければ意味を成さないことです。

しかしご安心を。GoogleのCardboardハコスコに代表される、段ボール製のゴーグルも最近では活発に発表されています。
また、「VRゴーグル」などで検索してみると、プラスチック製の比較的しっかりしたゴーグルも様々なものが発売されていることも分かります。
そしてどれもが1000〜3000円以内で購入することが可能です。

このように、圧倒的に安価にVRを始められるのもスマホVRのメリットです。

実際にスマホVRを作ってみよう

安価に体験できることは分かりました。しかしまだ読者の方の中には「でも作るのは大変なんでしょ?」と思われている方がいらっしゃるかもしれません。
しかし、それも心配無用です。

WebVRの波に乗るように、すでにいくつかのフレームワークが登場しています。
今回紹介するのは「WebVR Boilerplate」です。

これを使えば、非常に手軽にWebVR(とスマホVR)の環境を構築することができます。
このフレームワークはWebGLのライブラリとして有名なThree.jsをベースに構築されています。

Three.jsに触れたことがある読者の方であれば、いくつかのスクリプトを読み込ませ、数行書き出すだけですぐにでもWebVRに対応させることが可能です。
今回はこれを使って、ごく簡単なシーンのセットアップコードを見ながら、実際にVRコンテンツが手軽に作れることを実感してもらいたいと思います。
(もしすでにThree.jsでコンテンツを作ったことがある方は、ぜひご自分のコンテンツをWebVR化してみてください)

シーンの構築

まずはThree.jsを使ってシーンを構築していきます。
今回は長くなってしまうのでThree.jsの使い方などについての説明は割愛します。
が、ごく簡単なシーンですので使ったことがない方でも、なんとなくどんなことをやっているかは分かるかと思います。

ちなみに今回のデモはGithubにソースコードをアップしています。
また実際に動くものも公開しているので、どんなものかをすぐ見ることができます。

スマホで実際に実行した状態は以下のようになります。

demo-image アニメーションgif

// WebGLレンダラを生成
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);

// CanvasをDOMツリーに追加
document.body.appendChild(renderer.domElement);

// シーンを生成
var scene = new THREE.Scene();

// カメラを生成
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);

// VR用コントローラを生成
var controls = new THREE.VRControls(camera);

// VR用エフェクトを生成(2分割の画面を構築する)
var effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);

// VRマネージャの生成
var manager = new WebVRManager(renderer, effect);

まずはシーンのベースを構築します。
シーンオブジェクト、カメラオブジェクト、あとはそれらをコントロールするコントローラにマネージャ、と名前を見ればなんとなくどんなことをやってくれるかが分かるオブジェクトたちをセットアップしています。
Three.jsを触ったことがある人であれば何度も目にしている記述とほぼ同じことが分かると思います。

さて、土台を作ったらシーンの登場人物たちを作ります。
冒頭で説明した通り、今回は宇宙空間に地球が浮いているようなものを想定しているのでそれらを作っていきます。

// Skysphereの生成(星空)
var skysphereLoader = new THREE.TextureLoader();
skysphereLoader.load('img/bg_skyplane.png', onSkysphereTextureLoaded);
function onSkysphereTextureLoaded(texture) {
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(4, 4);

    var geometry = new THREE.SphereGeometry(5000, 128, 128);
    var material = new THREE.MeshBasicMaterial({
        map: texture,
        color: 0xffffff,
        side: THREE.BackSide
    });

    var skysphere = new THREE.Mesh(geometry, material);
    skysphere.position.z = 0;
    scene.add(skysphere);
}

// 地球オブジェクトの生成
var earth = new THREE.Object3D();
var earthLoader = new THREE.TextureLoader();
earthLoader.load('img/earth.jpg', onEarthTextureLoaded);
function onEarthTextureLoaded(texture) {
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;

    var geometry = new THREE.SphereGeometry(0.3, 32, 32);
    var material = new THREE.MeshLambertMaterial({
        map: texture,
        color: 0xffffff
    });

    earth = new THREE.Mesh(geometry, material);
    earth.position.z = -1;
    scene.add(earth);
}

// ライトの生成(地球を斜め上から照らしたような演出にします)
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);

これで宇宙(星空)と地球、そして太陽に照らされているような演出ができあがりました。
現時点で実行して見ると宇宙空間に地球が浮いている様子が描画されます。

earch-capture

さぁ、いよいよ最後の部分です。
VRモードで見るにはジャイロで動かして、さらに立体視できるように画面を分割して表示する必要があります。

ジャイロで動かしたり、地球を回転させたり、といったことを実現するにはそのためのループ処理(アニメーションループ)を実装します。
そのループ処理の中で地球の回転や、ジャイロをカメラに伝える処理を記述します。
それを実現するのが以下の記述です。

// アニメーションループ
var lastRender = 0;
function animate(timestamp) {
    var delta = Math.min(timestamp - lastRender, 500);
    lastRender = timestamp;

    earth.rotation.x += delta * 0.000015;
    earth.rotation.y += delta * 0.000025;

    // VRコントローラのupdate
    controls.update();

    // VRマネージャを通してシーンをレンダリング
    manager.render(scene, camera, timestamp);

    // アニメーションループ
    requestAnimationFrame(animate);
}

// アニメーションの開始
animate(performance ? performance.now() : Date.now());

アニメーションループ部分です。
どうですか? 拍子抜けしましたか?
見てみるとアニメーションのループの中で実際になにかしら計算っぽいことをしているのは、地球を回転させる処理だけです。
それ以外はすべて、VRコントローラとマネージャが引き受けてくれます。

あとはこれを実際に実行してみれば、冒頭で紹介したデモと同じ状態が再現されます。

いかがでしょうか。こうしたフレームワークを使うことで、WebVRとスマホVRは驚くべき手軽さで実現することができるのです。

WebVRでOculus Riftを動かそう!

前述まででいかに手軽にスマホVRが制作できることが分かっていただけたかと思います。
さて、だいーぶ前置きが長くなってしまいましたが、ここから本題です。

WebVRのAPIを利用してOculus Riftを動かすところを見てみましょう。
実のところ、このAPI自体も自分自身で触ることはほぼないでしょう。
前述したWebVR BoilerplateにはWebVRをラップしたいくつかの便利ライブラリが含まれています。

※ 現時点の最新仕様はWebVR1.0となっており、執筆時点ではまだ正式対応がされていないようですが、WebVR1.0向けのブランチが存在しているので、そちらをダウンロードしてきて利用してもいいでしょう。

WebVR Boilerplateを使って実装した上記の地球デモはすでにWebVRのAPIに対応した状態になっています。
(ただし、上でも触れた通り、Oculus Riftの最新のRuntimeが入った状態だと、masterブランチのものでは動作しません。また、WebVR1.0に対応したブランチであっても、WebVR1.0に対応しているのはChromiumの専用ビルドだけなので注意してください)

ごく簡単なセットアップだけでOculus RiftとスマホVRに両対応できるのはとてもメリットです。

ではいよいよWebVRのAPIを説明していきましょう。
・・・といきなり言われても、おそらくOculus Riftを持っている方のほうが少ないでしょう。
(なんせ製品版は10万円近くもしますからね)

なので今回は、WebVRのAPIがどんなものなのか、それをどう使うのか、ということを解説したいと思います。
最初に断っておくと、WebVRのAPI自体はとても簡単なものです。
事実、APIから取得できる頭の位置、回転の情報を取得してそれをThree.jsのカメラの位置や回転に変換して適用してやるだけです。
極論な例を挙げるなら、ジャイロセンサーの値をなにかしらのスマホコンテンツに利用するのとほぼ同じことと言えます。

デバイスから値を取り出し、それを使う。

本当にただこれだけです。

しかしVRを表現する上でスクラッチで書くには大変な部分もあります。
下のキャプチャのように、中央から半分に分割されたVRの動画や画像をよく見かけると思います。

oculus-scene

画面を半分にし、それぞれの視点(左右の目)から見た状況をレンダリングする必要があるのです。
(上の画像をよーく見ると、若干左右の画面に違いがあるのが分かると思います)

しかし今回は、WebVR APIの使い方のイメージを掴んでいただくために、上記のレンダリングについては触れません。
これをスクラッチでやろうとすると、行列の知識や3Dの表現方法についての前提知識が必要となってしまい、説明するにはさらに多くの文章を必要としてしまうため、今回は割愛させていただきます。
ただ上でも書いた通り、このあたりの処理を自前で書く、ということはほぼゼロと言っていいでしょう。

そのため、内部的にどういう動作をしているか、を理解するにとどめておくだけで十分だと考えています。

今回はThree.jsのリポジトリに含まれている、VRControlsの実装を参考に、WebVR1.0に対応させたコードを紹介します。

var vrDisplay;

// VR Displayオブジェクトを取得
navigator.getVRDisplays().then(function (displays) {
    if (displays.length === 0) {
        console.log('WebVR API is not supported.');
        return;
    }

    vrDisplay = displays[0];
});

// VRモードに移行
function toVRMode() {
    var canvas = document.getElementById('canvas');
    vrDisplay.requestPresent({
        source: canvas
    });
}

//////////////////////////////////////////////////

// カメラの位置、回転を制御
(function loop() {
    // VRDisplayに実装されている`requestanimationframe`を利用する
    vrDisplay.requestAnimationFrame(loop);

    var pose = vrDisplay.getPose();

    var orientation = pose.orientation;
    camera.quaternion.fromArray(orientation);

    var position = pose.position;
    camera.position.fromArray(position);
}());

とてもざっくりですが、WebVRのAPIを使った処理になります。

navigator.getVRDisplaysメソッドを利用してVRデバイスオブジェクトを取得します。
基本的にこのオブジェクトを介して処理を進めていくことになります。

注意 先にも書きましたが、getVRDisplaysはWebVR API1.0の仕様であり、それ用にビルドされたChromiumでしか動きません。(執筆時:2016.03.15)
FirefoxもWebVRに対応していますが、以前の仕様で実装されており、getVRDevicesメソッドがその役割になります。
しかし、取得できるデバイスオブジェクト自体が異なるため、今回紹介した方法では動きません。

上記で利用しているメソッドは以下です。

  • requestPresent
  • requestAnimationFrame
  • getPose
    • pose.position
    • pose.orientation

requestPresentメソッドはその名の通り、VRモードを表示するメソッドです。
フルスクリーンになり、上のほうで掲載した歪んだ画面を表示するためのものです。

requestAnimationFramewindowに生えているものとは別のものになります。
というのも、windowに生えているものは基本的に60Hzで動作するのに対し、VRではさらにその上の、90〜120Hzが要求され、frame数が合わないためです。
なので、VRモードではこちらを利用します。

一番注目してもらいたいのがgetPoseで取り出される値です。
読んで字のごとく、HMDの姿勢(pose)を取得するものです。

ここに、HMDがトラッキングした位置と回転情報が格納されています。
これをそのままカメラの制御に利用すれば、HMDの情報がそのままカメラに伝播し、結果としてVR空間を好きなように見渡すことが可能になる、というものです。

Three.jsを利用すれば、こうしたカメラなどが抽象化され、3Dに対しての知識があまりなくても実装することが可能です。
Oculusを持っている方はぜひ、簡単なサンプルでも構わないので作ってみてみてください。
自身が作ったものが目の前で動いているのは、どんなにシンプルなものでも感動するはずです。

コードを見てもらうと気づくと思いますが、カメラやエフェクトの部分以外はWebGLでコンテンツを作ることとまったく同じです。
あとはこれらを組み合わせてなにを作るか。アイデアさえ出てくれば、きっと様々なVRコンテンツを作ることができることと思います。
ぜひ、これを機会にVRコンテンツ制作に手を出してみてください。

ちなみに、WebVR1.0の実装についてもっと詳しく知りたい方は、こちらの記事にセットアップから実行までの解説が載っているので参考にしてください。(仕様はこちら

最後に

いかがだったでしょうか。
VRと言っても、コンテンツの作り方はWebGLとそう大きくは変わりません。
コンテンツの良し悪しはWebGLでのコンテンツの良し悪しに直結します。

ただVRならではの問題もあり、例えば目の前を覆ってしまうため、キーボードやマウスなどのデバイスを使っての操作はあまり向かないでしょう。
ゲームパッドのようなものはまだ大丈夫かもしれません。
そのため、UIに関してはまだまだこれだ、という状況になっておらず、今後も様々な研究結果が出てくるものと思われます。

ただどちらにせよ、UIの作り方自体はWebGL(3D)上での話になるため、制作過程についてはVRのために、というよりもWebGLでどう作るか、を学ぶことで解決できると思います。

VRという新しい技術をどう活かすか。それは制作者である読者の方の考え方次第で無限に広がっていくと思っています。
ぜひこの機会にVRコンテンツの制作を開始してみてください。
(例えばモデルルームをVRで観ることができる、というものは実際に行っている例があります)

筆者はスマホVRが市場を牽引してくれると信じています。
さらに言えば、Webで展開されるスマホVRがよりその力が強いでしょう。

しかしそのためにはみなさんの力が必要です。
ぜひいろいろなVRコンテンツを世に広め、VRを体験したことがある人を増やせるようにしていただけると幸いです。

Powered byNTT Communications

tag list

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