A-Frameで作ったWebVRにGoogle Polyの3DモデルをAPI経由で読み込んでみた ついでにA-Frameインスペクター使ってみた

Qiita投稿初心者です。よろしくお願いいたします。

# 前書き
前回の[OpenStreetMap(OSM)の3DマップとA-Frameを使ってWebVRを作ってみた](https://qiita.com/syntan/items/b89471803a27320256a6)で作成した東京駅前が誰もいなくて寂しかったので、お手軽に[Google Poly](https://poly.google.com/)の3Dモデルを読み込んで、遊んでみようと思います。
Polyの3Dモデルは前回のOpenStreetMapの3Dマップデータと同様に、ダウンロードしてローカルから読み込むこともできますが、PolyはAPIが公開されているので、せっかくなのでAPI経由で読み込んでみようと思います。

# 前提環境
* Webブラウザ：FireFox 55以降 記事中では78.0.2を使用

# 1. Google Poly API使用準備

## 1.1. APIキーの取得
@fromkkさまの[Poly APIをARKitで使ってみる](https://qiita.com/fromkk/items/01f85514d32f66cbc849) の `APIの利用方法` の記述が詳しいです。APIキーが取得できれば完了です。

## 1.2. APIを試しに呼んでみる

```
https://poly.googleapis.com/v1/assets/9C-MLNfxaor?key=[ここに1.1.で取得したAPIキー]
```

をブラウザで開くと、Polyのモデルの情報が入ったJSONが返ってくるのが確認できると思います。

```json
{
  "name": "assets/9C-MLNfxaor",
  "displayName": "Fox",
  "authorName": "Jake Blakeley",
  "createTime": "2019-09-03T19:45:04.338524Z",
  "updateTime": "2020-08-03T10:01:52.552642Z",
  "formats": [
    {
      "root": {
以下省略...
```

例示したURLの `9C-MLNfxaor` というのが3Dモデルの識別子です。この識別子はPolyで3Dモデル閲覧ページのURLから、確認することができます。例えば `9C-MLNfxaor` の閲覧ページは[https://poly.google.com/view/9C-MLNfxaor](https://poly.google.com/view/9C-MLNfxaor)です。

## 1.3. APIリファレンス
APIを呼んで戻ってくる値についてはここの記述が詳しいです。
[Poly API 公式リファレンス](https://developers.google.com/poly/reference/api/rest/v1/assets)


# 2. A-FrameへPolyの3Dモデルの読み込み

※今回はサーバーサイドの実装無しにHTMLとJavaScriptのみで実装するので、JavaScript内にAPIキーをベタ打ちしていきますが、本来はサーバーサイドでAPIを呼び出して、APIキーは秘匿するべきだろうと思います。その点あらかじめご了承ください。

## 2.1. HTMLコード

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello, VR Poly!</title>
    <!-- aframe-extras requires 0.9.X aframe -->
    <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
    <!-- https://github.com/donmccurdy/aframe-extras -->
    <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.0/dist/aframe-extras.min.js"></script>
    <script src="script/callPolyApi.js"></script>
  </head>
  <body>
    <a-scene background="color: #EEEEEE">
      <a-assets>
        <a-asset-item id="map" src="models/map.glb"></a-asset-item>
      </a-assets>
      
      <!-- light -->
      <a-light color="#FFEEEE" position="-1 1 0"></a-light>

      <!-- objects -->
      <a-entity id="map" 
                position="0 0 0" 
                rotation="0 0 0" 
                gltf-model="models/map.glb" 
                scale="1 1 1" 
                shadow="">
      </a-entity>

      <a-entity id="polyModel"></a-entity>

      <!-- movement control -->
      <a-entity id="rig"
          movement-controls
          position="0 0 0">
        <a-entity camera
                  position="0 1.6 0"
                  look-controls="pointerLockEnabled: true">
        </a-entity>
      </a-entity>

    </a-scene>
  </body>
</html>
```

[前回](https://qiita.com/syntan/items/b89471803a27320256a6)からの変更点は

* `script/callPolyApi.js` の読み込みの追加
* `id="polyModel"` のエンティティ追加

です。

## 2.2. JavaScriptコード

```callPolyApi.js
var request = new XMLHttpRequest();
request.open('GET', 'https://poly.googleapis.com/v1/assets/9C-MLNfxaor?key=[APIキー]', true);
request.responseType = 'json';

request.onload = function () {
  var data = this.response;
  console.log(data);

  var gltfUrl = ""
  data.formats.forEach(element => {
    if(element.formatType == "GLTF2"){
      gltfUrl = element.root.url;
    }
  });

  document.getElementById("polyModel").setAttribute("gltf-model",gltfUrl);
};

request.send();
```

`XMLHttpRequest` を使用してAPIを呼び出し、得られたJSONから `GLTF2` のurlを取得して、`id="polyModel"` のエンティティに追記しています。

## 2.3. 実行の様子
いでよfox！！
駅のモデルがローカル、foxがネットワーク経由なせいか、foxが少し遅れて登場します。
![実行結果01_狐.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/f32e500a-536f-6440-8c9b-f5d07d184adc.png)
foxさん近い近い！！
召喚座標とカメラの座標が同じなので、ドアップ登場になりました。
カメラをひいてみるとこんな感じです。
![実行結果02_狐.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/423ddff8-ab6f-b1c4-e2b4-3df1f6d19a06.png)
あらかわいい。ライトが画面左からの指向性ライト1つのみなので、右側が暗くてディテールが見えていないですね。

# 3. シーンの調整
コードと実行結果を行ったり来たりで調整することも可能ですが、A-Frameにはシーン調整に便利なインスペクターが用意されています。呼び出し方法は、シーンを表示しているブラウザ上で `Ctrl` + `Alt` + `i` です。
参考：[Visual Inspector & Dev Tools](https://aframe.io/docs/0.9.0/introduction/visual-inspector-and-dev-tools.html)

## 3.1. A-Frame インスペクター
`Ctrl` + `Alt` + `i` で開いた画面
![インスペクタ―01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/afbdf17a-a5f5-4c3a-111a-9a903df6809a.png)
インスペクターはブラウザの開発者ツールのように、コードを変更し変更結果をすぐに確認できるツールです。開発者ツールと同様に元のファイルを変更するものではないので、変更した値を使用したい場合は手動でのコピペが必要です。

インスペクタ―でのカメラの操作は以下の通りです。

* マウス左ボタンを押下しドラッグ：カメラの角度変更
* マウス右ボタンを押下しドラッグ：カメラの平行移動
* マウス中ボタン(スクロールボタン)を押下し上下ドラッグ：カメラの前後移動

## 3.2. 環境光の追加

まずはfoxのディテールが見えるように環境光を追加しましょう。
![インスペクタ―02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/5e44c674-7827-9e18-bf48-4504be0b2803.png)
画面左上の「＋」ボタンをクリックすると、新しいエンティティが追加され、画面右側に追加したエンティティのプロパティが表示されます。
![インスペクタ―03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/93e06403-ae37-2c40-fe8b-0d8e604cbaef.png)
上部の `<a-entity>` をクリックするとコンポーネントの選択画面が表示されるので、 `light` を選択します。
![インスペクター04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/c786e284-9167-15fc-026c-6501aac81787.png)
lightのプロパティ設定は、

* color：#333
* type：ambient

で設定しました。
![インスペクター05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/f78fb27e-ba0e-287a-5db7-2daf2954a401.png)

追加したエンティティのコードは、プロパティ設定画面の右上のボタンからコピーできます。
![インスペクター06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/53931b0a-1eb8-c6b8-6d6d-c0052cd7a75a.png)

コピーした文字列は以下です

```html
<a-entity light="type: ambient; color: #333"></a-entity>
```

これをindex.htmlに追記すると、そのまま使用できます。
追記位置は、 `<!-- light -->` と　`<!-- objects -->` の間あたりにでも。

## 3.3. 位置調整

次に、カメラの初期位置とfoxの初期位置が同じなので、位置を調整しましょう。
調整対象は `<a-entity polyModel>` です。
![インスペクター07.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/55a80370-8c17-0d49-8e77-d01ef086c6c2.png)
画面左のメニューで `<a-entity polyModel>` を選択すると、foxの周りに青い線でボックス、foxの手前に緑赤青の矢印が表示されます。
![インスペクター08.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/69235269-c79d-1915-9323-7989fa827c09.png)
青い矢印を左クリックドラッグで後ろに動かすとfoxが画面後ろに移動し、画面右のプロパティのpositionの三つ目の値が変更されます。
![インスペクター09.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/f22b789a-1929-7e7c-d25f-bb20eee15af7.png)
これで位置調整は完了です。

ライティングの調整と同様に、HTMLをコピーすると以下の文字列が得られます。

```html
<a-entity id="polyModel" position="0 0 -6.97721" gltf-model="https://poly.googleapis.com/downloads/fp/1596448912552642/9C-MLNfxaor/fgIw32pFZy_/model.gltf"></a-entity>
```

これは、APIを経由せずモデルを直接読み込むコードとなるため、 `position="0 0 -6.97721"` のみindex.htmlへ追記しましょう。

## 3.4. 調整後のHTMLコード全文

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello, VR Poly!</title>
    <!-- aframe-extras requires 0.9.X aframe -->
    <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script>
    <!-- https://github.com/donmccurdy/aframe-extras -->
    <script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.0/dist/aframe-extras.min.js"></script>
    <script src="script/callPolyApi.js"></script>
  </head>
  <body>
    <a-scene background="color: #EEEEEE">
      <a-assets>
        <a-asset-item id="map" src="models/map.glb"></a-asset-item>
      </a-assets>

      <!-- light -->
      <a-light color="#FFEEEE" position="-1 1 0"></a-light>
      <a-entity light="type: ambient; color: #333"></a-entity>

      <!-- objects -->
      <a-entity id="map" 
                position="0 0 0" 
                rotation="0 0 0" 
                gltf-model="models/map.glb" 
                scale="1 1 1" 
                shadow="">
      </a-entity>
      <a-entity id="polyModel" position="0 0 -6.97721"></a-entity>

      <!-- movement control -->
      <a-entity id="rig"
          movement-controls
          position="0 0 0">
        <a-entity camera
                  position="0 1.6 0"
                  look-controls="pointerLockEnabled: true">
        </a-entity>
      </a-entity>

    </a-scene>
  </body>
</html>
```

## 3.5. 調整後の実行の様子
![シーン調整後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/459a069a-33af-3daa-c0a0-ffa2ba8f6317.png)
こんにちはfoxさん！！

# 4. VRで実行した様子

いざHMDをかぶってfoxさんに会いに行きましょう。
HMDやキーボードでの操作は[前回](https://qiita.com/syntan/items/b89471803a27320256a6)の記事をご参照ください。

![VRで実行した様子.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673394/ad2025e1-aff1-5c67-87cd-3beffa60a6fa.gif)
思ってたよりずっと大きい！！なでなでしたい！！
そして人気が無い東京駅前に一匹の大きい狐が佇んでると、とてもファンタジー。

あと、gifアニメーションだと長い動画がアップロードできないので、ツイート動画の埋め込みしたいなあと思うところ…。次はツイッターアカウントを用意したいですね。

# ライセンス

記事中で使用した、オープンソースライブラリ、3Dモデルのライセンスです。

## コード
* A-Frame：[The MIT License Copyright © 2015-2017 A-Frame authors.](https://github.com/aframevr/aframe/blob/master/LICENSE)
* aframe-extras：[The MIT License (MIT) Copyright (c) 2016 Don McCurdy](https://github.com/donmccurdy/aframe-extras/blob/master/LICENSE)

## 記事内で使用したPolyの3Dモデル
* Fox copyright Jake Blakeley CC-BY [https://poly.google.com/view/9C-MLNfxaor](https://poly.google.com/view/9C-MLNfxaor)

## 地図データ
* © [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors

# 参考
* https://aframe.io/docs/0.9.0/introduction/