[連載] WebVR入門 vol.1


この記事は[WebVR Advent Calendar](http://qiita.com/advent-calendar/2015/webvr)14日目の記事です。


-------------------------------------------


さて、今週一週間記事を書き続けようと埋めまくったんですが、まったくノープランでしたｗ
なのでうまく着地できるか分かりませんが、WebVR入門と銘打って連載をしたいと思います。

この連載の目的は「WebVRってむずかしいんでしょ？　どうせ」って思っている人に向けて、「えっ、そんな簡単なら私もやってみようかしら？」って思わせるのが目的の入門記事連載です。

Firefoxの安定版ですでにWebVRの実装が取り込まれたのは[前回の記事](http://qiita.com/edo_m18/items/492f4e1620bbcf7b14e3)で書いた通りです。
つまりそれだけ期待している、ということでしょう。（だってまだOculus Rift、発売日さえ細かく決まってないのに）

個人的にもWebVRからVRが広まってくれると思っています。

ということで、今回は「WebVR Hello World」として、[Three.js]()を用いてWebVRコンテンツを作る部分までをやりたいと思います。

え、いきなりそこまで？ と思うかもしれませんが、それくらい簡単なんです。


## Three.jsを落としてくる

さて、WebGLを生で書いてそれを表示してさらにそれをWebVRで・・・というのでももちろんいいのですが、さすがにそうなると書くことが膨大になってしまうので、今回は[Three.js](http://threejs.org/)を使って書きたいと思います。

なにより、Three.jsのexampleの中にはすでにWebVRに対応するためのスクリプトも含まれているので楽ちんです。

## ファイルの準備

Three.jsを落としてきたら必要なJSファイルをコピーします。
使用するのは **three.js** でも **three.min.js** でもどちらでも構いません。



また今回は上で書いた通り、VR関係のものも利用するので以下のディレクトリにある2つのファイル（ **VRControls.js** と **VREffect.js** ）もコピーします。


▼ VREffect.js
![VREffect.jsの場所](https://qiita-image-store.s3.amazonaws.com/0/5616/39833e69-4123-1be1-c895-9224564cea5e.png "VREffect.jsの場所")

▼ VRControls.js
![VRControls.jsの場所](https://qiita-image-store.s3.amazonaws.com/0/5616/662f34bc-7b47-371d-9bf1-450605bb833a.png "VRControls.jsの場所")


コピーしたらそれを読み込みます。

```html
<script src="js/three.min.js"></script>
<script src="js/VRControls.js"></script>
<script src="js/VREffect.js"></script>
```

これで準備は終わりです。


## コードの記述

さて、準備が整ったのでコードを書いていきます。
といっても、今回の例で言えばThree.jsのHello Worldに毛が生えた程度しか変更点がありません。
なので、まずはバシッとコードを貼ってしまいます。

```js
(function () {
    'use strict';

    var width  = window.innerWidth;
    var height = window.innerHeight;

    // カメラ
    var camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000);
    camera.position.set(0, 10, 20);
    camera.lookAt(new THREE.Vector3(0, 0, 0))

    // レンダラ
    var renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(width, height);
    renderer.setViewport(0, 0, width, height);

    document.body.appendChild(renderer.domElement);

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

    // キューブ
    var material = new THREE.MeshLambertMaterial({
        color: 0xff0000
    });
    var geometory = new THREE.BoxGeometry(10, 10, 10);
    var mesh = new THREE.Mesh(geometory, material);
    mesh.position.set(0, -30, -30);

    // ライト
    var light = new THREE.DirectionalLight();
    light.position.set(0, 100, 100);

    scene.add(light);
    scene.add(mesh);

    // VRControls
    var controls = new THREE.VRControls(camera);

    // VREffect
    var effect   = new THREE.VREffect(renderer);
    effect.setSize(width, height);

    // アニメーションループ
    (function loop() {
        mesh.rotation.y += 0.01;
        controls.update();
        effect.render(scene, camera);
        requestAnimationFrame(loop);
    }());

    // リサイズ
    window.addEventListener('resize', function () {
        width  = window.innerWidth;
        height = window.innerHeight;
        effect.setSize(width, height);
        renderer.setSize(width, height);
        renderer.setViewport(0, 0, width, height);
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
    }, false);

    // ボタンクリック
    document.getElementById('btn').addEventListener('click', function () {
        effect.setFullScreen(true);
    }, false);

}());
```

いかがでしょう？
コードの行数もごく短いですし、Three.jsを触ったことがある人であればほぼ基本的なコードしかないことに気づくと思います。

違いはどこか。
それは以下の部分です。

```js
// VRControls
var controls = new THREE.VRControls(camera);

// VREffect
var effect   = new THREE.VREffect(renderer);
effect.setSize(width, height);

// 中略

controls.update();
effect.render(scene, camera);
```

まさに、今回のために読み込んだファイルで定義されている部分の呼び出しですね。
ただ、記述はほんとに簡単です。

あまりに短すぎて説明の必要がないとは思いますが、いちおう説明しておくと。

**VRControls.js** はOculus Riftのトラッキングを担当してくれます。
引数にカメラを渡して、あとはレンダリングループの中で `controls.update()` を呼んであげれば勝手にカメラの視点をHMD（ヘッドマウントディスプレイ）の位置に追従して動かしてくれます。

**VREffect.js** は、いわゆるVRコンテンツで見られる「画面を半分に割って視差を表す」処理を行ってくれます。
これを実行すると出力結果はこんな感じになります↓
![スクリーンショット](https://qiita-image-store.s3.amazonaws.com/0/5616/d22f53ec-4104-5caf-0de0-bcc6b0707c71.png "スクリーンショット")

画面が割れて、キューブがふたつに見えているのが分かると思います。
VREffectは引数にレンダラを受け取ります。このレンダラから値を取得して、適切に画面を半分にしてレンダリングしてくれる、というわけです。

あともうひとつの機能として、フルスクリーン対応があります。
Oculus Riftのコンテンツを見たことがある人は分かると思いますが、Oculusのコンテンツの場合、画面を少し歪ませる処理があります。
その処理はWebVRが担ってくれるのですが、その処理にはフルスクリーンにする必要があり、さらに引数にHMDのインスタンスを渡す必要があります。

が、そのへんの小難しい処理も **VREffect** がやってくれるので、使う分には以下のメソッドを呼ぶのみで実現できます。

```js
effect.setFullScreen(true);
```

めちゃめちゃ簡単ですｗ



さて、今回は以上です。
が、キャプチャを見てもらうと分かりますがだいぶ寂しいですねｗ
ただ、Oculus RiftをつないだPCでこれをFirefoxで見ると目の前でキューブが回転していることが確認できます。
ごく簡単なキューブだけでも、実際に自分で動かしてみるとまた違った感動があります。

今週の連載はこれを徐々にバージョンアップさせていく、という形でやっていこうと思います。

連載で使うコンテンツやコードは[Github](https://github.com/edom18/webvr-advent-calendar)にアップしていきます。

それから今回作成したコンテンツは[こちらで動作を見る](http://edom18.github.io/webvr-advent-calendar/step1/)ことができます。