ARKitで空間共有して端末間通信する方法22選

ARKit2.0で空間共有ができるようになったと話題でしたが、実はARKit1.0でもARKit1.5でも空間共有はできます。

しかし、もちろんARKit2.0になって選択肢の幅が広がりました。今記事では、**選択肢とその組み合わせ**のアイデアだけにフォーカスしたいと思います。(ARKitの使えるiOSデバイス間での通信を前提とします。)

# ARKitで空間共有するための方法22選
![image](https://pbs.twimg.com/media/DfAtqSTX0AATlrt.jpg)

まず、前提として次の①~④のステップを経て空間を共有して端末間通信することを考えます。

- **①iOSデバイス間で端末間通信する**
- **②ARKitで共通の原点を作り出す**
- **③ARKitで座標(原点)を一致させる**
- **④座標や角度を送受信する**

この方法がそれぞれいくつかありまして、

- ①iOSデバイス間で端末間通信する方法 * 3
- ②ARKitで共通の原点を作り出すための方法 * 4
- ③ARKitで座標(原点)を一致させるための方法 * 2
- ④座標や角度を送受信する方法 * 1

つまり、**3 * { (4 - 1(ARWorldMap)) * 2 + 1(ARWorldMap) } * 1= 22選**です。

②と③が紛らわしいですが、②原点を作るためのAnchorを用意することと③実際に座標を一致させることは別の作業です。([ARWorldMap](https://developer.apple.com/documentation/arkit/arworldmap)を使うときだけ②と③が一気にできます。)

①~④を順番に紹介したいと思います。

# ①iOSデバイス間で端末間通信する方法3選
![multipeer1.png](https://qiita-image-store.s3.amazonaws.com/0/111366/fe394a1d-976c-aa0d-3b63-1cd76373690a.png) 
[^image1]

- [MultiPeerConnectivity](https://developer.apple.com/documentation/multipeerconnectivity)
- [Firebase Realtime Database (Firestore)](https://firebase.google.com/docs/firestore/?hl=ja)
- [TwilioVideo](https://github.com/twilio/video-quickstart-swift)

上記の３つが僕が今まで試したことのある方法です。これらは比較的導入コストが低くプロトタイピングやスタートアップのアプリ開発に適していると思います。

他にもGoogleの[Neaby API](https://developers.google.com/nearby/)を使う方法、TwilioVideo以外のWebRTCを使った通信などもあると思いますが、僕はまだ実際に試したことがありません。iOSだけでなく例えばAndroidと端末間通信するためには考慮しなければいけないと思います。

# ②ARKitで共通の原点を作り出すための方法３選
![image3](https://docs-assets.developer.apple.com/published/bb066be074/f91a2410-22c6-4c15-9717-603f2b9370eb.png)
[^image3]

- [ARWorldMap](https://developer.apple.com/documentation/arkit/arworldmap)(iOS12.0~)
- [ARCore Cloud Anchors](https://developers.google.com/ar/develop/ios/overview)でAnchorを共有
- [ARImageAnchor](https://developer.apple.com/documentation/arkit/arimageanchor)(iOS11.3~)を使う
- デバイス同士の距離を指定してボタン押してもらう(手動)

ARKit2.0が追加されたARWorldMapがすごいのは、Mapを共有したら、**原点も一緒になることです。** つまりARWorldMapだけは次の③も一度にできます。ただ、Mapを作るためにある程度部屋を見回したりする動作をユーザーに強制する必要はあります。

# ③ARKitで端末間の座標（原点）を一致させるための方法2選
<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/a36799ed-648c-f5d3-0884-f2e3b8dfa79b.png" width=200>
[^image2]

ARWorldMapを使うときだけ②③が同時にできるのですが、それ以外のパターンが２つあります。

- [setWorldOrigin(relativeTransform:)](https://developer.apple.com/documentation/arkit/arsession/2942278-setworldorigin)(iOS11.3~)を使う
- 自分のデバイスから共有するデバイスの原点へ変換する行列を都度適用する

# ④座標や角度を送受信する方法１選
![1_ynzub0bsRqZ2H7CR2dL1yg.png](https://qiita-image-store.s3.amazonaws.com/0/111366/7cda5d8b-7326-9d73-ce6a-9c158bf5b438.png)

- [Codable](https://developer.apple.com/documentation/swift/codable)でModelをJSONにエンコードして送信

プロトタイピングも含めて何回か端末間通信をして座標などを送信しましたが、Codable一択かなと思います。JSONラッパーとしても標準でシンプルでパフォーマンスも良いのでCodableがベストプラクティスだと思っています。

# 組み合わせパターン

## パターンA...実装が早い (iOS11.3~)
- ①Firebase Realtime Database (Firestore)
- ②ARCore Cloud AnchorsでAnchorを共有
- ③setWorldOrigin
- ④Codable

## パターンB...オフラインでできて頻繁にデータを送受信できる (iOS11.3~)
- ①MultiPeerConnectivity
- ②ARImageAnchor
- ③setWorldOrigin
- ④Codable

## パターンC...位置共有の精度が高い (iOS12.0~)
- ①MultiPeerConnectivity
- ②③ARWorldMap
- ④Codable

## パターンD...iOS11.0~に対応させる (iOS11.0~)
- ①MultiPeerConnectivity
- ②デバイス同士の距離を指定してボタン押してもらう
- ③自分のデバイスから共有するデバイスの原点へ変換する行列を都度適用する
- ④Codable

# まとめ

ARKit 2.0が出たことでARWorldMapを使うのがベストかと思いきや、僕はパターンBが現状でベストプラクティスだと思っています。**空間共有をするプロセスが一番早くiOS11.3~対応**なためです。

しかし、アプリの用途によって位置共有のベストプラクティスは異なります。例えばsetWorldOriginのメソッドはiOS11.3からしか使えないので、アプリがiOS11以上を対応したいのならば別の方法を取らなければいけないからです。それぞれの実装方法については１２月中に[ARKit Advent Calendar 2018](https://qiita.com/advent-calendar/2018/arkit)の別記事にて紹介していきたいと思います！（ガチ）

ではまた明日！

[^image1]: https://blog.xamarin.com/send-the-monkey-a-message-with-multipeer-connectivity/
[^image2]: https://www.xlsoft.com/jp/blog/blog/2017/11/16/post-2608/
[^image3]: https://developer.apple.com/documentation/arkit/creating_a_multiuser_ar_experience