vue
OculusGo
aframe

Aframe + Vue を使ってOculusGoでWebVRを(なるべく簡単に)はじめる

はじめに

Oculus Rift Advent Calendar 2018の14日目の記事です。
OculusといえばUnityやUE4による開発がメジャーですが、中にはブラウザ上でVRをやってみたい!という変態人たちも結構います。
しかし、いざ AframeReact360(元ReactVR) のページを見ても「よくわからん・・・」という人が多く、断念している人が多いと思います。

Aframeって何?

ざっくり説明すると、ブラウザ上でHMDやCardboard対応の3Dレンダリングを簡単に行えるフレームワーク(内部的にはthree.jsのVR向けラッパーライブラリ群)です。 公式サイトのデモでブラウザ上で3Dモデルが表示されていると思います。

右下のアイコンをクリックすると

といったVRおなじみの画面が出てくると思います。

Aframeを実際に使用するまでがわかりにくい

公式サイトのインストール項目を見ると、英語慣れしていないと何をすればよいのかわかりにくいです。
ここの項目は開発スタイルごとのHowTo的な話が盛り込んであり、Aframeを使うという意味では下の2項目になります。

Include the JS Build

HTMLからビルド済みファイルを使用する方法です。scriptタグを使ってCDNからファイルをロードします。

<head>
  <script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
</head>

Install from npm

パッケージ管理ソフトのnpmからAframeを利用できるようにします。単純にモジュールをローカルに持ってくるだけで実際に使用する時はnodeモジュール利用時の作法を守っていく必要があります。(本来 npm init を行ったり、コマンドも npm install aframe --save としてモジュールをdependenciesに追加する必要があるのですが、説明がありません)
さらに項目の続きに

  • If you use npm, you can use angle, a command line interface for A-Frame. angle can initialize a scene template with a single command:

とあり、angle自体は簡易的なジェネレータで、テンプレートのpackage.jsonに記述されている構成が古い(webpackが2.7で止まってたり、babelの設定が含まれていない、など)ため、これを使ってAframeの開発することはおすすめしません。

Vue CLIを使ってみる

Vue CLIはVueのためのCLIですが、ジェネレータが優秀で、Webpack導入からBabelの設定まで設定してくれるため、Aframeの開発にも利用すると、開発が非常に楽になります。
とりあえず、Vue CLIのインストールは省略し、ジェネレータから作成する場合に、どのようにAframeを含めていくかやっていきます。

ジェネレータを使用してプロジェクト作成する

コンソールから以下のコマンドを打ちます。[任意のプロジェクト名]の箇所は自分の好きな名前をつけてください

vue create 任意のプロジェクト名

するとCLIの選択画面が出てくるので、下にカーソルをあわせてエンターキーを押します

Vue CLI v3.1.3
┌───────────────────────────┐
│  Update available: 3.2.1  │
└───────────────────────────┘
? Please pick a preset: (Use arrow keys)
   default (babel, eslint) 
❯  Manually select features 

とりあえずはBabelLinter / Formatter にチェックがはいっていればOKです。エンターキーを押します

? Check the features needed for your project: 
❯◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

ESLint + Standard configにカーソルを合わせてエンターキーを押します

? Pick a linter / formatter config: 
  ESLint with error prevention only 
  ESLint + Airbnb config 
❯ ESLint + Standard config 
  ESLint + Prettier 

Lint on save にチェックが入っていればOKです。エンターキーを押します

? Pick additional lint features: (Press <space> to select, <a> to toggle all,
 <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

どちらでも良いのですが、個人的に In dedicated config files のほうが管理しやすいです。エンターキーを押します

? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use a
rrow keys)
❯ In dedicated config files 
  In package.json 

これまでのプリセットを保存して別のプロジェクトで使い回すか?という内容が表示されます。 N をタイプしてエンターキーを押します

? Save this as a preset for future projects? (y/N) 

インストールが終了するまで待ちます。終わったらエディタでプロジェクトが入ったフォルダを開きます。以下の例ではvscodeを利用しています。

code 任意のプロジェクト名

Aframeを追加する

package.json があるプロジェクトのルートディレクトリに移動し、以下のコマンドを利用します。 パッケージ管理ソフトはyarnをおすすめします。

yarn add aframe

HelloWorldのコードを書いていく

(任意).eslintrc.js書き換え

Linterに手を加えます。好みの問題になるのですが、自分は普段このような設定を使っています。個々の設定の意味はESLintのルールを見ると良いでしょう

module.exports = {
  root: true,
  env: {
    node: true,
  },
  'extends': [
    'plugin:vue/essential',
    '@vue/standard',
  ],
  rules: {
    'no-extra-semi': 'warn',
    'no-undef': 'warn',
    'quotes': ['error', 'single'],
    'space-before-function-paren': ['error', 'never'],
    'arrow-parens': 0,
    'generator-star-spacing': 'off',
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
  },
  parserOptions: {
    parser: 'babel-eslint',
  }

main.js書き換え

エントリーポイントになっているmain.jsを書き換えます。ファイルはsrcフォルダ内に入っています。
import 'aframe'を追加します。

import Vue from 'vue'
import App from './App.vue'

import 'aframe'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

App.vue書き換え

App.vueはルートVueインスタンスになるもので、ここに子になるコンポーネントが追加されていきます。同じくsrcフォルダ内にあります。
.vueファイルはテンプレートとスクリプトに別れており、template(html)の記述とjsのスクリプトを一つにまとめて書くことができます。
以下のように書き換えます。

<template>
  <div id="app">
    <aframe-window></aframe-window>
  </div>
</template>

<script>
import AframeWindow from './components/AframeWindow'

export default {
  name: 'app',
  components: {
    AframeWindow
  }
}
</script>

HelloWorld.vue削除、AframeWindow.vueを新規作成

プロジェクトのルートディレクトリ以下から、 /src/components/HelloWorld.vue を削除、同じディレクトリにAframeWindow.vue を追加し、以下のよう内容にします

<template>
  <div id="aframe-window">
    <a-scene background="color: #ECECEC" embedded>
      <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-scene>
  </div>
</template>

<style>
@media only screen and (min-width: 640px) {
  #aframe-window {
    width: 640px;
    height: 320px;
    margin-left: auto;
    margin-right: auto;
  }
}

@media only screen and (max-width: 640px) {
  #aframe-window {
    width: 320px;
    height: 320px;
    margin-left: auto;
    margin-right: auto;
  }
}
</style>

<script>
export default {
  name: 'AframeWindow'
}
</script>

これだけでAframeで開発を行う準備ができました。ここからVueやAframeの世界がまっています!

ローカルサーバーを起動する

上記ファイルを保存後、以下のコマンドを実行します

yarn run serve

起動に成功すれば以下のようなメッセージが出ます。
PCとOculusGoが同じルーターに繋がっている場合は Network の箇所のアドレスをOculus Goのブラウザで開くことができます。
スクリプトのファイルを保存するたび、自動ビルド+ブラウザリロードがかかるので、すばやく開発をしていくことができます。

 DONE  Compiled successfully in 1179ms

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.***.***:8080/

Aframeの開発にVueを使うメリットは?

今回は時間がなくてあまり説明できませんでしたが、Aframeの開発にVueを用いる理由として、

  • AframeはDOM操作を意識しないとオブジェクト間の連携ができない。が、Aframe自体はDOM操作が得意ではない
  • VueはDOM操作を意識しなくてもDOM構造をいじることができるので、よりプログラマブルに記述できる
  • AframeとVueどちらもコンポーネント指向のため、書いたコードがどのように動くのか把握しやすい
  • Vue CLIがめんどくさい設定を殆どやってくれるので、初期設定で悩むことが少ない

など、お互いのメリットを生かして利用できるため、それぞれ別の目的のフレームワークでありながら、共存させることができ、とても強力な組み合わせになっています。
また、AframeもVueもドキュメントが豊富で、リファレンスに困ることが少ないというメリットもあります。

Vueについてはこちらを参照するとわかりやすいかもしれません。