VRコンテンツをHTMLとJavascriptで作る

メインはバックエンド、時々フロントエンドエンジニアの古見澤(こみざわ)です。
久しぶりのブログ記事となります。

先月に発売されたOculusQuestというVRヘッドセットを購入し、最近プライベートではVRゲームを楽しんでいます。Quest良いですね、6DoFのスタンドアロン型で回転できる腕も振り回せる〜とか色々語りたいのですが、脱線しすぎで長くなるのでこの場ではやめておきます。

さて、VRコンテンツというとUnityUnrealEngine4(UE4)で作られる事が多いと思いますが、Web系の言語でも作れる事はご存知でしょうか。現時点ではまだ一般的とは言い難いですが、今回はWebでのVRコンテンツ作成について取り上げようと思います。

WebVR

WebVRとは、Webブラウザ上からVRヘッドセットの位置・向き・傾きや加速度などの情報を取得できるJavascriptのAPIです。現在の最新バージョンは1.1で、2017年にリリースされています。将来的にはVRだけでなくAR(拡張現実)にも対応したWebXR Device APIというものに置き換えられる予定となっています。

WebVRhttps://webvr.info/

実際のところ、WebVRはVR機器から情報を取得するものであって、VRコンテンツを生成するものではありません。そのためVRコンテンツ自体はthree.jsなどを利用しWebGLで描画して作っていく必要があるのですが、フルスクラッチで作っていくのは中々大変です。しかし、そういった開発を容易にするためのフレームワークも存在します。今回はそのフレームワークの中からA-Frameというものをご紹介します。

A-Frame

A-Frameは、WebVRの機能をHTMLのような記述で使う事が出来るようになるフレームワークで、内部ではthree.jsが使われています。MozillaのVRチーム内で開発され、VRブラウザのSupermediumやGoogleの開発者達によって保守されています。github上ではMITライセンスでソースも公開されています。

f:id:komi_asial:20190626170847p:plain

A-Framehttps://aframe.io/

公式ページのShowcaseでどのようなWebサイトが作れるか、その一端を見る事が出来ます。

「BeatSaber」というリズムにあわせ箱を斬るVRゲームがありますが、あのゲームのカスタム曲をブラウザからプレビューできる「BeatSaver Viewer」というWebSiteや・・・

f:id:komi_asial:20190626171603p:plain
BeatSaver Viewer

こちらもリズムゲームですが、「Sound boxing」ゲームもWebサイト上からプレイすることが出来ますね。

f:id:komi_asial:20190626171935p:plain
Soundboxing WebVR

ちなみにこれらサイト上で「Ctrl + Alt + i」を押すとA-Frame用のインスペクタが起動します。ページ内の構成が確認できるので、参考になるものもあるかと思います。

エンティティ・コンポーネント・システム(ECS)

A-Frameはゲーム開発でよく利用される、エンティティ・コンポーネント・システムを採用しています。
シーン(VR内の世界だと思ってください)に存在する全ての実態オブジェクトをエンティティ、振る舞いを記述して定義したものをコンポーネントと呼び、役割や必要に応じてエンティティに対してコンポーネントを付与する形を取ります。

例えば、次の例では空間上に平面と箱が存在するだけですが

See the Pen
A-Frame 物理演算の付与前
by komi_asial (@komi_asial)
on CodePen.

ライブラリを読み込み、平面と箱のエンティティに対し物理演算コンポーネント(dynamic-body、static-body)の記述を追加するだけで・・・

See the Pen
A-Frame 物理演算の付与後
by komi_asial (@komi_asial)
on CodePen.

(表示された直後に動きがあるので、見直す場合は右下のRerunを押してください

箱が落下し、床の上でバウンドしたり転がったりしますね。(Rerunを押す度に微妙に結果が変わります)

このように、エンティティに対して物理演算を利用した振る舞いが追加されました。

エンティティは目に見える物体だけでなく、3D空間を表示しているカメラもエンティティの一つです。カメラはデフォルトで「look-controls」と「wasd-controls」というコンポーネントが付与されており、それぞれ大雑把に「VRヘッドセットが回転した、マウスを動かした、タッチスクリーンでドラッグした時にエンティティを回転させる」「キーボードのWASDキーや矢印キーが押下されたら移動する」という振る舞いが定義されていて、このおかげでVR上での視点が移動するわけです。

コンポーネント

これまでに説明してきたコンポーネントは、自分で作ってももちろん良いのですが、github上には既に多数のコンポーネントが公開されており、ライブラリを読み込むだけで便利な機能をすぐに使えるようになります。VRでの体験を豊かにするものもあれば、開発者がアプリケーションを作りやすくするためのものもあります。

NPM上をaframe-componentで検索

いくつかご紹介します。

A-Frame Extras

Extrasという名が示す通り、基本のA-Frameには含まれていないものの使い勝手がいいコンポーネントが揃っています。多種多様なコントローラーに対応するもの、ジャンプができるようになるもの、glTF・FBX・objファイル形式といったモデルを読み込むローダー、コントローラーの握る動作により「掴める」ようになるもの、海のように水が揺れる床を描画するもの、その他にも色々。

https://github.com/donmccurdy/aframe-extras

aframe-haptics-component

VRコントローラーを振動させる事ができるコンポーネントです。VR世界においてバイブレーション機能は効果的で、視覚と聴覚に加えて触覚にも訴えるだけでリアルさが大きく増します。モノを掴んだり武器を振るったりメニューを選択した時など、利用用途は多いと思います。

https://github.com/supermedium/superframe/tree/master/components/haptics/

aframe-firebase-component

Firebaseと連携するためのコンポーネントです。これを利用してマルチユーザーのVRアプリを作る事ができます。なおこのコンポーネントの内部でも使われていますが、aframe-broadcast-componentという、WebSocketを使ってブロードキャストするためのコンポーネントもあります。

https://github.com/supermedium/superframe/tree/master/components/firebase/

aframe-state-component

Web系のフロントエンド開発ではお馴染み「ステート」を扱うためのコンポーネントです。この後少し話題に出てきます。

https://github.com/supermedium/superframe/tree/master/components/state/

A-FrameをReactと組み合わせる

こちらは紹介程度にします。「aframe-react」という、A-Frameを利用したコンテンツをReactで開発するためのライブラリがあります。

https://github.com/supermedium/aframe-react

Reactに慣れた開発者にとっては良いものかと思うのですが、冒頭で作者は以下のように述べています。

I recommend using vanilla A-Frame and aframe-state-component with static templating over aframe-react. React wastes a lot of cycles and incurs a lot of memory garbage. aframe-react is often abused where it is too easy to place 3D/real-time logic at the React layer, causing poor performance (e.g., doing React renders on ticks). aframe-react applications frequently ignore the prescribed ECS framework of A-Frame. Internally, React does tons of computation to compute what changed, and flushes it to the entire application. It is apparent React ecosystem does not care much about memory as most examples allocate functions and objects in the render method, and where immutables are popular. With only ~10ms per frame to do all computation, there is little room for React's massive system.

簡単にまとめると、"Reactを使うと様々な理由でパフォーマンスが低下するから、A-Frameのまっさらな状態から「aframe-state-component」と「static templating」を使った開発をおすすめするよ" という事らしいです。こちらについては実際に比較したことが無いのでわかりませんが、高パフォーマンスを求められるようなものを作る場合は考えた方がよいかもしれませんね。


実機(OculusQuest)で試してみた

まずはこちら。右手のコントローラーから出るレーザーポインターを水面に浮かぶ球体に向けてトリガーを引くと、その間だけ球体が少し大きくなる・・・というものを作ってみました。VR用コントローラーが無いとレーザーポインターが表示されないので注意。

See the Pen
A-Frameを試してみた
by komi_asial (@komi_asial)
on CodePen.

f:id:komi_asial:20190627134744g:plainf:id:komi_asial:20190627134830g:plain

実際にアクションを起こしているのがマウスでは無くVRコントローラーという違いはありますが、考え方は一緒。であるならばフロントエンド開発の知識がそのまま使えます。


もう一つ、Super Handsというコンポーネントのサンプル集の中の一つ。ブロックを持ち上げて箱の中に入れると色が変わって落ちてくるというもの。

SuperHands example1_1
目の前の箱を色々な角度から眺める

コントローラーのトリガーを握る事で物が掴め、手を開けば離す。加速度センサーも入っていますから、物を投げる事もできます。

f:id:komi_asial:20190627131010g:plainf:id:komi_asial:20190627131547g:plain

今回は明らかにサンプルっぽいものを試しましたが、冒頭で上げたA-FrameのShowcaseで紹介されているもののように本当にゲームをプレイしているようにしか見えないクオリティのものも作れるようですね。

最後に

数年前までVRコンテンツというのはニッチな遊びという印象が強かったと思っています。実際5年前にOculus Rift DK2が出た時にも私は購入していくつかVRコンテンツを試してみましたが、当時は画面は荒く、対応するアプリやゲームを広めるプラットフォームは整備されておらず、3Dテレビみたいに消えていくのかなと思っていたこともありました。しかしハードウェアが少しずつ進化してきて、少しずつ地味ながらゆっくりとVRが広がりかけてきているかなという印象はあります。それでもまだ数年はかかるとは思いますが。

Web技術でVRコンテンツを作るのは大変かもしれませんが、VR毎の専用プラットフォームを通す事なく、あるいはいちいちデバイスを開発者モードにして手動でインストールすることなくVRコンテンツを提供できるのは良いかなと思いました。アプリ審査もいりませんしね。

今後ARと統合し、スマートフォンの対応具合によっては更にWeb技術で開発するという選択肢も増えてくるのではないかなと思っています。

また、VRを体験したことが無い人は是非一度機会があれば遊んでみてください。できれば顔の傾きだけしか検知できない3DoFではなく、前後左右上下の動きも検知でき実際に自分の足で動き回れる6DoF対応の機材を使った体験をおすすめします。