WebVR(ブラウザーでVRデバイスが使用できるAPI)を軽く試して気づいたこと

個人的に望んでいたAPIの実装が開始されたというニュースを知りとてもうれしいです。
それが、WebVR
Oculus RiftなどのVRデバイスがブラウザーで(直接)使用するためのAPIです。
現在は、ChromeとFirefoxのWebVRを実装した特別な？ビルド版が配布されています。
[Chrome](http://blog.tojicode.com/2014/07/bringing-vr-to-chrome.html)
[Firefox](http://blog.bitops.com/blog/2014/08/20/updated-firefox-vr-builds/)
今のところ、両ブラウザーともにOculus Riftのみ対応しており、Chromeは近いうちにcardboardにも対応(つまりはAndroid用？)するようです。また、MozillaスタッフのブログではLeap Motion, PrioVR, Sixense Stemといったデバイス名も見られますので将来これらのデバイスに対応するのではと期待します。
Chromeの[サンプルページ](http://media.tojicode.com/webvr-test/)のソースを見ればデバイスの取得、センサーデータの取得といったWebVR APIの(Oculus Riftに関する)一通りの使用方法が確認できます。
このWebVRを軽く試してみて気づいたこと書きます。
**※Chromeでしか試していません。**

###Oculus Riftは2つのデバイスで認識される
---

```js:VRデバイスを列挙するコード
if (navigator.getVRDevices) {
  navigator.getVRDevices().then(EnumerateVRDevices);
} else if (navigator.mozGetVRDevices) {
  navigator.mozGetVRDevices(EnumerateVRDevices);
}

function EnumerateVRDevices(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[i] instanceof HMDVRDevice) {
      hmdDevice = devices[i];
      break;
    }
  }
  // hmdDeviceのhardwareUnitIdと同じPositionSensorVRDeviceを取得
  for (var i = 0; i < devices.length; i++) {
    if (devices[i] instanceof PositionSensorVRDevice &&
      (!hmdDevice || devices[i].hardwareUnitId == hmdDevice.hardwareUnitId)) {
                    sensorDevice = devices[i];
    }
  }
}
```
Oculus Riftは、HMDVRDeviceとPositionSensorVRDeviceの2つが認識されます。
* HMDVRDevice
ディスプレイ側のデバイスで、画面サイズや目の位置(getEyeTranslation関数)、FOV(getRecommendedEyeFieldOfView関数)の情報を取得することができます。
* PositionSensorVRDevice
センサー側のデバイスで各センサーの各種情報(getState関数)を取得することができます。
###デバイスを接続していなくても動作確認できる
---
上記のVRデバイスを列挙するコードを、デバイスを接続しないで実行するとEnumerateVRDevices関数のdevices引数にはデバッグ用の仮想的なデバイス(deviceName="Mockulus Rift")が渡されますので、デバイスがなくても動作を確認することができます。  

###複数デバイスにも対応？
---
私はOculus Riftを複数所有していないため実際に確認してませんが、HMDVRDevice,PositionSensorVRDeviceそれぞれにdeviceIdプロパティ, hardwareUnitIdプロパティがあるのですが、これらのプロパティの値(文字列)の最後には番号があり、１つですと"0"となっており、デバイスが増えるごとにこの番号が増えていき列挙時に取得できると予想します。

###WebGLでないと動作しない
---
サンプルコードを見ると、canvasをフルスクリーンすることで歪みエフェクトをかけたレンダリングが行われます。

```js:歪みエフェクトをかけて表示するコード
if (canvas.webkitRequestFullscreen) {
  canvas.webkitRequestFullscreen({ vrDisplay: hmdDevice, /*vrDistortion: false*/ });
} else if (canvas.mozRequestFullScreen) {
  canvas.mozRequestFullScreen({ vrDisplay: hmdDevice });
}
```

ならば2Dコンテキストのcanvasでも行けるのではと予想したのですが、試してみるとフルスクリーンを実行したとたんにページが落ちます。
![chrome_error.png](https://qiita-image-store.s3.amazonaws.com/0/17554/557a7563-ac6f-b9f4-59f2-ac77f55aaeab.png)

###目の横方向位置合わせはコーディングが必要？
---
[WebVR Test](http://media.tojicode.com/webvr-test/)
こちらのサンプルで、目の位置を設定するコードが

```js
var eyeOffsetLeft = hmdDevice.getEyeTranslation("left");
var eyeOffsetRight = hmdDevice.getEyeTranslation("right")
cameraLeft.position.sub(eyeOffsetLeft);
cameraRight.position.sub(eyeOffsetRight);
```

となっておりますが、サンプルを実際にOculus Riftで見てみると左右の間隔が離れていました。
もうひとつのサンプル[Quake 3 level renderer](http://media.tojicode.com/q3bsp/)をOculus Riftで見てみると、間隔があっていました。
Quake 3 level rendererでは、getEyeTranslation関数で取得した目の位置と、getRecommendedEyeFieldOfView関数で取得したFOVから、ビューマトリックスおよびプロジェクションマトリックスを算出しています。
将来的には上記のコードできっちり間隔が合ったものとなるのかは不明ですが、
算出して設定するサンプルをあげているため、やはりコーディングが必要なのかもしれません。

###あとがき
---
現状では、トラッキング情報を取得するために別途EXEを実行したり、歪みエフェクトをかけるためにOculusRiftEffect.jsを使用したり(または自力でシェーダーを組んだり)しなければならないのですが([Oculus RiftをWebで使用するためのライブラリのまとめ](http://qiita.com/gtk2k/items/5e26336d0b267822d2c4))、そんなことする必要なく使えるようになるはすごくコーディング及び環境構築が楽になります。