Poly APIをARKitで使ってみる

[ARKit Advent Calendar 2017](https://qiita.com/advent-calendar/2017/arkit)の11日目です。
[Timers Inc.](http://timers-inc.com)でiOSエンジニアをしています[かっくん a.k.a. fromKK](https://twitter.com/fromkk)と申します。
今年の[WWDC](https://developer.apple.com/videos/play/wwdc2017/602/)でAppleが`ARKit`を発表した時に現場に居たのですが、凄く盛り上がったのを未だに覚えています。
業務でも`ARKit`は少しずつ活用し始めているのですが、2017年10月末にGoogleがリリースした`Poly`と組み合わせた機能もちょうど本日[リリース](http://famm.us)しました🎉

その機能の開発中の2017年11月末に[Poly API](https://developers.google.com/poly/)もリリースされました。
流石に業務で入れるのは間に合わなかったのですが、この度[2017年 AKIBA.swift忘年回](https://classmethod.connpass.com/event/73341/)にて登壇する事になり、それに合わせて少し触ってみた事をまとめておきます。

# [Poly](https://poly.google.com/)

![poly.png](https://qiita-image-store.s3.amazonaws.com/0/2846/cf934058-9f45-80ce-db26-6834dcad3915.png)

[Poly](https://poly.google.com/)は2017年10月末にGoogleリリースした3Dモデルが自由にダウンロード出来るサイトです。
様々なクリエイターが作った3Dデータが無料でダウンロード出来るので独自に3Dモデルを作る時間が無い場合は、[Poly](https://poly.google.com/)からモデルをダウンロードして利用する事も検討して良いと思います。
但し、利用する際にはライセンスに注意が必要です。
大半の3Dデータは**CC-BY**というライセンスになっており、製作者を画面に表示する必要がありますので、実際に利用する際にはご注意下さい。

# [Poly API](https://developers.google.com/poly/)

![poly_api.png](https://qiita-image-store.s3.amazonaws.com/0/2846/ea203592-6b17-9882-93e7-4ebbe1d2f474.png)

[Poly API](https://developers.google.com/poly/)は2017年11月末に[Googleが発表](https://blog.google/products/google-vr/introducing-poly-api/)した[Poly](https://poly.google.com/)のデータをダウンロードしてアプリ等で利用出来る様にしたプラットフォームです。
まだ、出来る事は少なくて、assetの検索、詳細の取得、ユーザー毎の投稿の取得、ユーザーが高評価にしたものリストの取得しか出来ません。
assetの検索、詳細の取得はAPIキーさえあれば利用可能ですが、ユーザー毎の投稿の取得、ユーザーが高評価にしたものリストの取得はOAuthでの認証が必要です。
Google製の[Sample](https://github.com/googlevr/poly-sample-ios)もありますので参考にして頂ければと思います。

# APIの利用方法

先にGoogle APIのConsole画面で[Poly API](https://developers.google.com/poly/)を有効にしておく必要があります。

<img width="1039" alt="Screen Shot 2017-12-10 at 16.52.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/2846/f05ebcc1-4029-c7fc-2b4a-bfa3d201d5d6.png">

その後Poly APIの[Document](https://developers.google.com/poly/develop/ios)からAPIキーを取得する事が出来ます。

<img width="1201" alt="iOS_Quickstart_ _ _Poly_ _ _Google_Developers.png" src="https://qiita-image-store.s3.amazonaws.com/0/2846/47dff035-8e60-016b-ca2e-a8db23784d82.png">


# API概要

ドメインは`https://poly.googleapis.com`で共通しています。

## v1.assets

| Methods | Path |
| ------- | ---- |
| get | GET /v1/{name=assets/*} |
| list | GET /v1/assets |

検索や詳細の取得が出来ます。URLの後ろにAPIキーを付与するだけの簡易認証で利用出来ます。
(例: `https://poly.googleapis.com/v1/assets?key=YOUR_API_KEY` )

## v1.users.assets

| Methods | Path |
| ------- | ---- |
| list | GET /v1/{name=users/*}/assets |

ユーザーが投稿したasset一覧です。OAuth認証が必要なので今回は試せていません。

## v1.users.likedassets

| Methods | Path |
| ------- | ---- |
| list | GET /v1/{name=users/*}/likedassets |

ユーザーが高評価にしたもののasset一覧です。OAuth認証が必要なので同じく今回は試せていません。

# PolyのデータをARKit/SceneKitで利用する

Assetの中に`formats`というオブジェクトがあります。
Polyでは3Dデータの登録時に`.obj`ファイルと`.mtl`ファイルをアップロードするのですが、他のデータ形式にも変換されるのか様々なデータ形式が格納されている事がありますので`formats`の中から`formatType`が`OBJ`の物を検索して利用する必要があります。
`format`には`root`というオブジェクトと`resources`という配列があるのですが、それぞれ`.obj`ファイルのURLと`.mtl`ファイルのURLを格納しています。データによっては`.jpg`や`.png`等のテクスチャファイルを格納している事がある様です。
これらのURLのファイルを全てダウンロードしてローカルの同じフォルダに格納します。
全てのファイルをダウンロードした後は下記の様に`.obj`ファイルのURLを使用すれば`SCNNode`として利用出来ます。

```swift
import SceneKit
import SceneKit.ModelIO
import ModelIO

// MDLAssetインスタンスを生成
let mdlAsset = MDLAsset(url: objURL)
// テクスチャを読み込む
mdlAsset.loadTextures()
// SCNNodeを生成
let node = SCNNode(mdlObject: mdlAsset.object(at: 0))

```

# [PolyKit](https://github.com/fromkk/PolyKit)

今回触ってみて、Googleが定義している構造をマッピングしたり、Assetから複数のファイルをダウンロードする処理を書くのが少し面倒だったのでライブラリ化しました。

[https://github.com/fromkk/PolyKit](https://github.com/fromkk/PolyKit)

Carthageに対応したのでインストールは下記の様に`Cartfile`に書いて**Terminal.app**で`carthage update --platform ios`を実行してプロジェクトにインポートするだけで利用出来ます。

```
#Cartfile
github "fromkk/PolyKit"
```

## 使い方

### 検索

検索は先にクエリーを作成してAPIのインスタンスに渡すとassetの検索が可能です。

```swift
import PolyKit

let query = PolyAssetsQuery(keywords: "Cat", format: Poly3DFormat.obj)
let polyApi = PolyAPI(apiKey: "Poly API Key is HERE!!!")
polyApi.assets(with: query) { (result) in
    switch result {
    case .success(let assets):
        self.dataSource.assets = assets.assets ?? []
    case .failure(_):
        self.showFetchFailedAlert()
    }
}
```

### `.obj` と `.mtl`のダウンロード

assetのダウンロードは`downloadObj`関数を実行すれば必要なファイルをダウンロードした後で`.obj`のローカルURLを取得する事が出来ます。

```swift
import PolyKit

let asset: PolyAsset = ...
// Download obj and mtl files from Poly
asset.downloadObj { (result) in
    switch result {
    case .success(let localUrl):
        let mdlAsset = MDLAsset(url: localUrl)
        mdlAsset.loadTextures()
        let node = SCNNode(mdlObject: mdlAsset.object(at: 0))
        // do something with node
    case .failure(let error):
        debugPrint(#function, "error", error)
    }
}
```

# まとめ

APIをラップしただけのライブラリですが利用が随分と簡単になったかと思います。
特にこれまでは3Dデータを動的に利用する様なアプリを作るのは大変でしたが、[Poly](https://poly.google.com/)のお陰で`ARKit`や`SceneKit`のアプリ開発も幅が広がっているなと感じます。
既に[Poly](https://poly.google.com/)には沢山の3Dデータがあり、今も続々とファイルが増えているので、今後のアプリやゲーム制作でもどんどん活用していきましょう⤴️
[PolyKit](https://github.com/fromkk/PolyKit)を使ってみて良いなと思った人は良かったら⭐️下さい❗️

## P.S.

今はAPIキーを利用しただけの機能しか利用出来ないのですが、GoogleのOAuthの利用の仕方ご存知の方いましたら、ご教授、[Pull Request](https://github.com/fromkk/PolyKit/pulls)お待ちしています🙇🏻‍♂️

[English ver is here](https://medium.com/@fromkk/use-poly-api-for-arkit-e053d352f1f7)