ブラウザで動くAR名刺を作った（執筆中）

みなさん名刺は持っていますか？
もっているそこのあなた、まさか紙の名刺なんていう時代遅れなものじゃありませんよね？（言い過ぎ）
時代はAR/VRです、名刺もAR化しちゃいましょう！

というわけでAR空間で見る名刺「AR名刺」を作りました。
紙の名刺と違って動きがつけれるので、人それぞれ特有の自分名刺をつくることができます。
AR名刺がどんなものか分からない方は[こちら](https://twitter.com/OsFalmer/status/1008736572185903105?s=20)をご覧ください。

最近はARKitを使って誰でも簡単にネイティブのARアプリを作れるようになっています。
しかし今回はブラウザ上で動くWebアプリとして作っています。
Webアプリである利点として、インストールの手間がなく、URLを開きさえすれば楽しめるという点があります。
名刺という性質上そんなに長く遊ぶものでもないため、サクッと遊んでもらうにはWebアプリが適しているというわけです。
ではブラウザで動くAR名刺を手順を順に説明していきます！

（将来ハンズオンをすることを見越してハンズオン風に書いています。[github](https://github.com/Khmer495/ar_meishi_handson)）

# 必要な知識
- HTML：動かすだけならHTMLのみで十分です。
- Javascript：タップ動作などを追加するなど応用的なことをする際にが必要となります。

# フレームワーク・ライブラリ
- [A-Frame](https://aframe.io/)：VR用のフレームワークです。AR空間内にオブジェクトを表示させるコードも、こちらのフレームワークに従って記述します。
- [AR.js(v0.9.0)](https://github.com/jeromeetienne/AR.js)：A-FrameをAR用に変換した、マーカーベースARのライブラリです。マーカーベースARとは、画像などの何らかのマーカーをカメラで認識すると、マーカー上にオブジェクトが表示されるタイプのARです。**v0.8からv0.9にかけて一部の記法が新しくなっているので注意してください。**

# Step1：マーカー上にオブジェクトを表示させる
いきなりコードをドンッと。

```html:index_step1.html
<!DOCTYPE html>
<html>
<head>
  <script src='https://aframe.io/releases/0.9.2/aframe.min.js'></script>
  <script src='https://raw.githack.com/jeromeetienne/AR.js/2.0.8/aframe/build/aframe-ar.js'></script>
</head>
<body style='margin: 0px; overflow: hidden;'>
  <!-- debugUIEnabledをtrueにすると、デバッグ情報が表示される。 -->
  <a-scene embedded arjs='debugUIEnabled: false;'>
    <!-- マーカーを設定。デフォルトではpresetにhiroとkanjiが設定可能。 -->
    <a-marker preset="hiro">
      <!-- 立方体を描画 -->
      <a-box position='0 0.5 0' material='color: yellow;'></a-box>
    </a-marker>
    <a-entity camera></a-entity>
  </a-scene>
</body>
</html>
```

こちらのコードをどこかにホスティングし、スマホで開いてください（面倒くさい方は[こちら](https://khmer495.github.io/ar_meishi_handson/index_step1.html)から）。
するとカメラを起動するか聞かれるので、許可してください。
カメラで下のHiro画像を見てみると・・・？
<img src="https://raw.githubusercontent.com/Khmer495/ar_meishi_handson/master/hiro.png" width="300">
黄色い箱が画像の上に現れたでしょうか？
ARなのでマーカーを認識できる限り側面等を見ることができます。

出てこない方はマーカーに光の反射等がないようにして見るようにしてみてください。
端末によって出なかったりする場合もあるようです。

##  コードの解説
### おまじない
```html
<!DOCTYPE html>
<html>
<head>
  <script src='https://aframe.io/releases/0.9.2/aframe.min.js'></script>
  <script src='https://raw.githack.com/jeromeetienne/AR.js/2.0.8/aframe/build/aframe-ar.js'></script>
</head>
<body style='margin: 0px; overflow: hidden;'>
  <!-- debugUIEnabledをtrueにすると、デバッグ情報が表示される。 -->
  <a-scene embedded arjs='debugUIEnabled: false;'>
・・・中略・・・
  </a-scene>
</body>
</html>
```
こちらはいわゆるおまじない的な部分ですね。そのまま書いちゃいましょう。

### マーカー
```html
<!-- マーカーを設定。デフォルトではpresetにhiroとkanjiが設定可能。 -->
<a-marker preset="hiro">
・・・中略・・・
</a-marker>
```
こちらはオブジェクトを表示させるためのマーカーの設定です。
presetとして先程使ったhiroと、もう一つ[kanji](https://raw.githubusercontent.com/Khmer495/ar_meishi_handson/master/kanji.png)があります。
自分で好きなマーカーを設定することもできます（後でやります）。
`<a-marker>`の間にARで表示するオブジェクトを書いていきます。

### オブジェクト
```html
<!-- 立方体を描画 -->
<a-box position='0 0.5 0' material='color: yellow;'></a-box>
```
Step1では`<a-box>`を使って立方体を描画しています。
A-Frameで用意されている図形は利用できます。
[こちら](https://aframe.io/docs/0.9.0/primitives/a-box.html)の左サイドバーのPRIMITIVES以下を参照してください（一部図形でないものも含みます）。
`position`でオブジェクトを表示する位置をします。
3つの値はそれぞれx、y、z軸を指し、それぞれマーカーを真上から見たときに右、手前、下方向が正の方向となります（下図参照）。
y=0だとマーカーの表面にオブジェクトが描画され干渉しあって汚くなるので、0.5だけ浮かして表示しています。
<img src="https://raw.githubusercontent.com/Khmer495/ar_meishi_handson/master/axes_directions.png" width="300">


# Step2：オブジェクトにアニメーションをつける
Step1でオブジェクトを表示させることができたので、次に回転などのアニメーションをつけてみましょう。
`<body>`の内側を以下のように変更します。

```html:index_step2.html（bodyの内側）
<script>
  // a-sceneより先に宣言する必要あり
  AFRAME.registerComponent('marker', {
    init: function () {
      // マーカー検出時にアニメーション開始
      let marker = this.el;
      marker.addEventListener('markerFound', function () {
        document.getElementById('obj').setAttribute('animation__scale', 'enabled: true');
      });
    }
  });
</script>

<a-scene embedded arjs='debugUIEnabled: false;'>
  <a-marker preset='hiro' marker>
    <!-- 三角錐を描画 -->
    <!-- 最初の3秒で大きさの倍率を0から1に -->
    <!-- その後3秒かけてxyz軸方向それぞれ360度回転をループ -->
    <a-tetrahedron id='obj' material='color: red;' position='0 1.5 0' scale='0 0 0'
      animation__scale='property: scale; dur: 3000; from: 0 0 0; to: 1 1 1; easing: linear; enabled: false;'
      animation__rotation='property: rotation; dur: 3000; from: 0 0 0; to: 360 360 360; easing: easeInOutCubic; loop: true; startEvents: animationcomplete__scale;'
    >
    </a-tetrahedron>
  </a-marker>
  <!-- カメラを設定 -->
  <a-entity camera></a-entity>
</a-scene>
```

お試しだけしたい方は[こちら](https://khmer495.github.io/ar_meishi_handson/index_step2.html)から。
マーカーは同じく[hiro](https://raw.githubusercontent.com/Khmer495/ar_meishi_handson/master/kanji.png)です。

Step2では三角錐を表示させます。
またアニメーションとして、はじめの3秒で大きさの倍率を0から1にし、その後3秒かけてxyz軸をそれぞれ一定角度回転させることを繰り返します。

## コードの解説
### マーカーの検出
```html
<script>
  // a-sceneより先に宣言する必要あり
  AFRAME.registerComponent('marker', {
    init: function () {
      // マーカー検出時にアニメーション開始
      let marker = this.el;
      marker.addEventListener('markerFound', function () {
        document.getElementById('obj').setAttribute('animation__scale', 'enabled: true');
      });
    }
  });
</script>
```
アニメーションはデフォルトではページを読み込んだ時点から開始してしまうため、いざマーカーを認識したときにはアニメーションが途中だったり終わっていたりという可能性があります。
なので、マーカーが読み込まれた瞬間からアニメーションを開始するロジックをここに書いています。
マーカーにはイベントとして`markerFound`と`markerLost`が用意されています。
`markerFound`が発火したときにアニメーションを開始（有効化）するようにしています。

### アニメーション
```html
<a-tetrahedron id='obj' material='color: red;' position='0 1.5 0' scale='0 0 0'
  animation__scale='property: scale; dur: 3000; from: 0 0 0; to: 1 1 1; easing: linear; enabled: false;'
  animation__rotation='property: rotation; dur: 3000; from: 0 0 0; to: 90 180 360; easing: easeInOutCubic; loop: true; startEvents: animationcomplete__scale;'
>
</a-tetrahedron>
```
`<a-tetrahedron>`は三角錐のオブジェクトです。

アニメーションは`animation`または`animation__name`という属性をつけることで追加できます。

`property`はアニメーションの種類です。
ここでは大きさの倍率の`scale`と軸回転の`rotation`を使っています。

`dur`はアニメーションの継続時間です。
単位はミリ秒です。

`from`、`to`はアニメーションを開始時、終了時の状態を表します。
`scale`では3軸ともに倍率を0から1に、`rotation`では3軸順に0度から90, 180, 360度回転させています。

`easing`ではアニメーションの加速度を設定します。
A-Frameで用意されているものは[こちら](https://aframe.io/docs/0.9.0/components/animation.html#easings)から確認できます。
easingそのものについては[こちら](https://ics.media/entry/18730/)でわかりやすい解説が行われています。
今回は`scale`では終始同じ速度で動くものを、`rotation`では初めと終わりは速度が早く、真ん中は遅いものを使っています。

アニメーションの再生のタイミングの設定方法は主に2つあります。
1. 何も設定しない。ページの読み込みと同時にアニメーションが開始します。
2. 他のアニメーションの終了を検知して開始する。
`scale`では1が、`rotation`では2が用いられています。

`scale`は最初のアニメーションですが、マーカーが認識されるまで開始して欲しくありません。
そこで`enabled`を`false`に設定することで、アニメーションを無効化し、マーカーが認識されたときにjsでこの値を`true`に変更しています。

`rotation`は`scale`のアニメーションが終わり次第開始させます。
`startEvents`に監視したいアニメーションの名前を入れた`animationcomplete__name`を指定することで、連続的にアニメーションを発火させることができます。
注意点として、アニメーションの名前は**同じオブジェクトの中**のものしか参照できません。
違うオブジェクトのアニメーションを監視したい場合は別途jsを書く必要があります。

`loop`を`true`にすることで、アニメーションが繰り返されます。
アニメーション開始時の状態は終了時の状態に関わらず、`from`に設定した状態にリセットされます。

他の`property`などアニメーションのドキュメントを確認したい方は[こちら](https://aframe.io/docs/0.9.0/components/animation.html)をご覧ください。