A-Frameで視点によるインタラクティブ操作を実現する

※2016年11月頃のメモです


## 動作環境
| 項目 |   内容  |
|:------------:|:------------:|
| OS |     macOS Sierra 10.12.3     |
| A-Frame |   0.3.0   |
|   Chrome |     55.0.2883.95 (64-bit)     |

## VR空間での操作
スマホでVRコンテンツにアクセスした場合、基本的にスマホをVRゴーグルにセットするため画面をタップすることができません。
先日発表されたGoogleの[Daydream](https://arvr.google.com/daydream/)やその他特殊なVRゴーグルでVR空間上の操作を可能にしているものもありますが、多くのVRコンテンツでは**視点によるクリック**を実現しているものがほとんどです。
WebVRのフレームワーク『A-Frame』でも視点による制御が可能で、A-Frameらしくタグだけで視点による制御を実装することが可能です。

## 視点によるインタラクティブ操作
今回はデモとして視点によるインタラクティブ操作を簡易的に体験できるページを作成しました。
シンプルなページですが、雰囲気はつかめると思います。
※ブラウザの設定によっては正しく動作しない可能性があります

[デモページ](https://thomi40.github.io/aframe/030/sample-cursor/)

デモページにアクセスすると画面中央に青色のリングが表示されていますが、これがいわゆる『視点』となっています。
この視点(リング)がオブジェクトに当たると**クリックした**と判定される仕組みです。

デモページのVR空間には正面に5つのオブジェクトが用意されていますが、それぞれのオブジェクトを一定時間見つめる(照準を合わせる)とクリックイベントが発生し、事前に設定したイベントを開始させることができます。
各オブジェクトに設定したイベントは以下の通り。
なお、画面下側にある2つの立方体のオブジェクトに対してもクリックイベントは発生しますが、各オブジェクトにイベントを設定していないため、何も変化しません。

| プリミティブ | イベント |
|:-----------:|:------------:|
| 左側の球体 | 非表示 |
| 右側の球体 | 視点を合わせたときに拡大 |
| 上手の球体 | リンク先へジャンプ(別のVR空間) |
| 下側2つの立方体 | クリックの検知なし |

## ソースコード
サンプルのソースコードはこちらです。

```html
<!DOCTYPE html>

<head>
  <title>A-Frame</title>
  <script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
</head>

<body>

  <a-scene>
    <a-camera position="0 0 0">
      <a-entity cursor="fuse: true; fuseTimeout: 1000"
                       position="0 0 -1" 
                       geometry="primitive: ring"
                       scale="0.03 0.03 0.03" 
                       material="color: blue; shader: flat">
        <a-animation begin="cursor-fusing" easing="ease-in" attribute="scale"
                               fill="none" from="0.03 0.03 0.03" to="0.001 0.001 0.001"></a-animation>
      </a-entity>
    </a-camera>

    <a-sphere position="-5 2 -7" color="#EF2D5E">
      <a-animation begin="click" attribute="scale" dur="500" easing="ease-in-sine" to="2 2 2"></a-animation>
      <a-animation begin="mouseleave" attribute="scale" delay="500" to="1 1 1"></a-animation>
    </a-sphere>

    <a-sphere position="0 6 -7" color="skyblue" id="sample-obj"></a-sphere>

    <a-sphere position="5 2 -7" color="red">
      <a-animation begin="click" attribute="visible" dur="5000" to="false" repeat="indefinite">
    </a-sphere>

    <a-box position="5 -3 -7" color="skyblue">
      <a-animation attribute="rotation" from="0 0 0" to="0 360 0" repeat="indefinite" easing="linear"></a-animation>
    </a-box>

    <a-box position="-5 -3 -7" color="skyblue">
      <a-animation attribute="rotation" from="0 0 0" to="0 360 0" repeat="indefinite" easing="linear"></a-animation>
    </a-box>


  </a-scene>

  <script type="text/javascript">  
    var clickElement = document.getElementById("sample-obj");
    clickElement.addEventListener("click", function() {
      location.href = "https://thomi40.github.io/aframe/030/sample-030/";
    },false);
  </script>

</body>

</html>
```

クリック以外にもアニメーションやJavaScriptによるイベントを設定したため、少し長くなってしまいましたが、たった40行ほどでVR空間の構築とインタラクティブな操作を実装することができました。
早速コードの詳細を見ていきましょう。 
A-Frameの基本的な使い方は以下の記事でも解説しているため、詳細は以下の記事をご覧ください。

[A-Frameを使ったVRコンテンツ開発入門](https://qiita.com/thomi40/items/dfc4175efece38ab5747)

### A-Frameの読み込み
```html
<head>
  <title>A-Frame</title>
  <script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
</head>
```
今回もA-FrameでVRコンテンツを作成するため`<head>`タグ内でA-Frameを読み込みます。
A-Frameのバージョンは 2016/11/08 現在で最新の`0.3.0`を使いました。

### カメラ・視点の設定
```html
<a-camera position="0 0 0">
    <a-entity cursor="fuse: true; fuseTimeout: 1000" 
            position="0 0 -1" 
            geometry="primitive: ring" 
            scale="0.03 0.03 0.03" 
            material="color: blue; shader: flat">
    <a-animation begin="cursor-fusing" easing="ease-in" attribute="scale" 
                    fill="none" from="0.03 0.03 0.03" to="0.001 0.001 0.001"></a-animation>
    </a-entity>
</a-camera>
```
こちらが今回のメインである視点に関する実装です。
#### Camera
VRシーンに照準を加えるため`<a-camera>`を定義します。
`<a-camera>`タグ内部で文字通り`<a-entity>`として`cursor `(カーソル)を設定します。
これによりVRシーンにリング状の視点が出現します。

#### cursor
`cursor="fuse: true; fuseTimeout: 1000" `のように`cursor`に`fuse`を設定することで、『指定した時間見つめた場合にイベントを発生させる』といった制御ができます。
今回は`fuseTimeout: 1000`として1秒間見つめたときにイベントを発生するよう設定しました。
他のエンティティとして設定したのは以下の通り。 

| コード | 詳細 |
|:-----------:|:------------:|
| geometry="primitive: ring" | 視点の形をリング状に |
| scale="0.03 0.03 0.03" | 視点をあらわすリングのサイズ |
| material="color: blue; | リングのカラーを`blue`に指定 |
| shader: flat | `flat`を設定することで光源からの影響を排除 |
 
#### animation
A-Frameでは`<a-animation>`タグによるアニメーションの設定が可能です。
今回は視点によるインタラクティブ操作をよりわかりやすくにするため、クリックイベントが発生するまでのフィードバックをリングの縮小(アニメーション)で表現しました。
A-Frameでは`attribute `に`scale`を設定することでオブジェクトのサイズを制御することができます。
今回のサンプルで`<a-animation>`タグに設定した属性はこちら。

| 属性 | 詳細 |
|:-----------:|:------------:|
| begin="cursor-fusing" | アニメーションの発生するタイミングを指定<br>`cursor-fusing`を設定することで視点を合わせた(正確には`cursor`の`fuse`の)タイミングでアニメーションが始まります |
| easing="ease-in" | アニメーションのeasing(緩やかさ)を指定<br>`ease-in`はアニメーションが加速していくようなイメージ |
| fill="none" | アニメーションが発生していないときのサイズを指定<br>`none`ではアニメーション終了後に元のサイズに戻る |
| from, to | `from`で指定したサイズから`to`で指定したサイズまで大きさを変更する |


ソースコード後半部分でも各オブジェクトに対してアニメーションを設定していますが、詳細の解説は本題から外れるため今回は割愛します。
`<a-animation>`タグの機能について詳しく知りたい方は公式のドキュメントを参考にしてみてください。
[Animations – A-Frame](https://aframe.io/docs/0.3.0/core/animations.html)

### VRシーンにリンクを設定する
```html
<script type="text/javascript">  
  var clickElement = document.getElementById("sample-obj");
  clickElement.addEventListener("click", function() {
    location.href = "https://thomi40.github.io/aframe/030/sample-030/";
  },false);
</script>
```

A-Frameで構築したVRシーンにリンクを貼り付ける方法はいくつかありますが、今回はJavaScriptで実装しました。
大まかに解説すると`sample-obj`のIDを設定したオブジェクトに`location.href`でリンクを設定し、イベントの発火タイミングとして`click`を設定しています。
今回はリンクとしてA-Frameで作成した簡易的なVRシーンを設定しました。
このようにリンクを設定することで別のVR空間に移動することができるので、簡単なアプリを作ることもできそうですね。

### 参考リンク  

[A-Frame – Make WebVR](https://aframe.io)