手軽にVRで遊んでみたい。

私ごとですが少し前にVRヘッドマウントディスプレイを買いました。
ひとしきり動かして、自室から一歩も出ないで筋肉痛になり、運動不足を感じたあたりで考える。

せっかくあるのだから他にも何かに使いたい。
でも Unity とか Unreal Engine とか触ったことないんだよね。
もっと気軽にできないかな。

***

# WebVR

web ブラウザ上での VR 表現を可能にする API
qiita にもこれを執筆している時点で127記事とそれなりの量の記事がある。

ブラウザ上でVR体験が可能であり、webアプリを公開さえすればURLを共有するだけで良い。
なにかしらのDLやインストールなどは不要。(ただし対応したブラウザは必要)

しかも対応したスマホがあればそちらでも閲覧可能。

というわけで WebVR を触ってみることにしました。

***

fire fox は普通に対応しているみたいだがよく使うのは chrome なので chrome で動かしてみよう。
chrome での WebVR は試験的な機能であり、動かすなら [chrome://flags/](chrome://flags/) から WebVR の利用フラグを立てなければいけないらしい。
さらに HTC Vive を使うなら OpenVR support とかいうフラグも立てて、、、と思ったら WebVR のフラグに以下のような文言が。

> This flag is deprecated and will be removed as soon as Chrome 79. This feature will eventually be replaced by the WebXR Device API.

どうやら WebVR は chrome Ver.79 で削除されて、WebXR Device API に移行するとのこと。
(しかも mac の chrome では WebVR flag が見つからなかった。(?))

実際に仕様を見に行っても WebXR Device API に置き換えが進んでいると書いてある。

***

# WebXR

では WebXR Device API とはなんぞや。

そもそも XR とは VR・AR・MR などの仮想現実を利用する技術の総称とのこと。
つまり WebXR Device API は WebVR に限らず WebAR などの体験も提供するAPIらしい。

この API に関しては chrome が Ver.79 で正式に対応を表明している。
手持ちのブラウザが対応しているかはサンプルページを表示すればわかるだろう。
[https://immersive-web.github.io/webxr-samples/](https://immersive-web.github.io/webxr-samples/)

ただしHMDを使うなら [chrome://flags/](chrome://flags/) 以下のフラグは設定しなければならないらしい。
・XR device sandboxing -> Disabled
・使用するHMDに対応した flag -> Enabled
　(HTC vive なら OpenVR support、 Oculus系なら Oculus VR support)
***

ともあれ、WebXR Device API も依然 W3C で策定中
[WebXR Device API W3C Working Draft, 10 October 2019](https://www.w3.org/TR/webxr/)

あまりこの辺りは気にせず今回は WebVR を作りたい。せめて Demo くらい触りたい。

(そもそも自分でこれらの API を直接叩くことがほぼない。使用するライブラリが対応しているかだけ確認しておこう。)

***

# A-Frame

少し探してみたところ、一番手軽そうだった [A-Frame](https://aframe.io/) を動かしてみることにしました。


何が手軽かというと、まず[公式 Docs](https://aframe.io/docs/1.0.0/introduction/) に記載されている文言がこれ。

> A-Frame can be developed from a plain HTML file without having to install anything.

何もインストールせずに素の HTML だけで開発できる。

HTML の `<head>` に A-Frame を include するだけ。

```html:demo
<html>
  <head>
    <script src="https://aframe.io/releases/1.0.1/aframe.min.js"></script>
  </head>
  <body>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>
  </body>
</html>
```

公式のデモのコードが以上で終了です。
非常に簡単。

***

また、簡単なデモを自身で作成する手順が MDN web Doc にまとまっていて、これにしたがってデモを作成しようとしました。
[A-Frameを使った基本的なデモの作成](https://developer.mozilla.org/ja/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_A-Frame)

※ただし、このデモが結構古い。
すでに A-frame は v1.0.0 がリリースされていますが、MDN web Doc に書いてある文章がこちら。

> A-Frame の現在のバージョンは 0.3.2 で、まだまだ実験的な段階ですが、既に動作しており、すぐにブラウザで試すことができます。デスクトップやモバイル (iOS や Android) の Oculus Rift、GearVR、HTC Vive で動作します。

例えば、DLが面倒なので上記 demo のように src を直接取得。
`<a-cube>`を置こうとした時点でつまづく。
出てこない。

公式ドキュメントをみても`<a-cube>`がそもそも見当たらない。代わりに`<a-box>`がいる。
そういえばさっきの demo も使っていたのは`<a-box>`
これはいかん。

***

mozilla には見切りをつけて、先ほど`<a-cube>`を探している間に見つけた公式の GUIDES に従います。
[https://aframe.io/docs/1.0.0/guides/building-a-basic-scene.html](https://aframe.io/docs/1.0.0/guides/building-a-basic-scene.html)

このデモに従えばシンプルな箱を表示することに成功しました。

こちらのデモは現行バージョンに即しており、丁寧に進行するので内容は割愛。

***

また、ここまででは VR デバイスを使えば動き回れるにしろ、ただ 3D オブジェクトを画面上に配置しただけ。
PC に接続するような HMD を持っているならコントローラーでこちらから干渉できるコンテンツは作れるのだろうか。

A-frame はコントローラーの認識も可能です。
[https://aframe.io/](https://aframe.io/) のデモの内、タイトル横にコントローラーアイコンが記載されているものはコントローラーを認識し、銃を撃つなどの操作が可能です。

***

# 参考文献
[WebVRを触ってみる](https://qiita.com/shiruco/items/6d5ca9c9bbd715676a48)
[WebVRだのWebXRだの状況をまとめてみた](https://qiita.com/emadurandal/items/baf68501b3a50b9a2b17)
[WebAR の現状確認 2019 Winter](https://qiita.com/ikkou/items/c32d57e30b28068b268d)
[WebVR Spec](https://immersive-web.github.io/webvr/)
[WebXR Device API W3C Working Draft, 10 October 2019](https://www.w3.org/TR/webxr/)
[A-frame](https://aframe.io/)