Unity ARKit Pluginの基本的な使い方まとめ

本日、会社でARKitとWebRTCのデモと技術解説をまとめたサイトを公開しました。

・ARKit Examples [http://arkit.r-u.co.jp/](http://arkit.r-u.co.jp/?ref=qiita)

・WebRTC Examples [http://webrtc.r-u.co.jp/](http://webrtc.r-u.co.jp/?ref=qiita)


ARKit Examplesでは、プログラミング的な解説というよりは、ARの体験を作る上での技術的な解決策について主に触れたので、
ここではその前のARKitをUnityで動かすための基本的なクラスを解説できればと思います。


# Unity-ARKi-Pluginの入手
Unityのアセットストアで公式のプラグインが提供されています。

Unity ARKit Plugin - アセットストア
https://www.assetstore.unity3d.com/jp/#!/content/92515

基本的には上記と同じものですが、Bitbucketから最新のものを取得することも可能です。

Unity-Technologies / Unity-ARKit-Plugin — Bitbucket
https://bitbucket.org/Unity-Technologies/unity-arkit-plugin


# 基本的なクラス

最低限ARKitを動かすには下記の3クラスが必要です。
## UnityEngine.XR.iOS.UnityARVideo
iOSデバイスのカメラの映像をCommandBuffer経由でUnity内のCameraに描画するクラス。カメラにAddComponentして使用します。
ClearMaterialプロパティには_YUVMaterial_を設定してください。

またCameraにSkyBoxなどが映ると、カメラの映像が隠されてしまうので、Cameraの_Clear Flags_は_Depth Only_に設定する必要があります。

## UnityARCameraNearFar
Unity内のCameraの_Clipping Planes_の_Near/Far_を適切に設定するクラス。メインカメラにAddComponentして使用します。

## UnityARCameraManager
 Cameraの動きを端末の動きと同期させるほか、いくつかの項目を設定するクラス。任意のGameObjectにAddComponentして、Cameraの参照を渡して使用します。


![setting.png](https://qiita-image-store.s3.amazonaws.com/0/103384/671a2059-aa9d-49d2-c040-8b7e97a0990e.png)

この状態で、実行中にMainCameraのPositionをDebug.Logなどで確認すると、
MainCameraの位置がカメラの動きに同期して動いていることがわかります。

## UnityARSessionNativeInterface
また、重要なクラスとして_UnityARSessionNativeInterface_があります。
こちらは名前の通り、ネイティブのARKitとの橋渡しを行う役割を持っており、
後述の検出結果の取得はこのクラスのdelegateとして受け取ることが可能です。


# ARKitの検出した特徴点を受け取る
ARKitの検出した特徴点の更新は
_UnityARSessionNativeInterface.ARFrameUpdatedEvent_
というdelegateメソッドで受け取ることが可能です。

```
public void Start()
{
   UnityARSessionNativeInterface.ARFrameUpdatedEvent += ARFrameUpdated;
}
	
public void ARFrameUpdated(UnityARCamera camera)
{
   Vector3[] pointCloud = camera.pointCloudData;
}
```

_UnityARCamera_に_pointCloudData_プロパティがあり、
特徴点の位置がVector3の配列で格納されています。

なお、Unity ARKit Plugin内のサンプルでは、
_PointCloudParticleExample_というクラスで該当の処理が実装されています。



# ARKitの検出した平面情報（床情報）を受け取る
ARKitの検出した平面情報は
_UnityARSessionNativeInterface.ARAnchorAddedEvent_
_UnityARSessionNativeInterface.ARAnchorUpdatedEvent_
_UnityARSessionNativeInterface.ARAnchorRemovedEvent_
という3つのdelegateメソッドで受け取ることが可能です。

```
public void Start()
{
   UnityARSessionNativeInterface.ARAnchorAddedEvent += AddAnchor;
   UnityARSessionNativeInterface.ARAnchorUpdatedEvent += UpdateAnchor;
   UnityARSessionNativeInterface.ARAnchorRemovedEvent += RemoveAnchor;
}
	
public void AddAnchor(ARPlaneAnchor arPlaneAnchor)
{
   〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
}

public void RemoveAnchor(ARPlaneAnchor arPlaneAnchor)
{
   〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
}

public void UpdateAnchor(ARPlaneAnchor arPlaneAnchor)
{
   〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
}
```

_ARPlaneAnchor_という構造体に平面情報が格納されています。

平面情報をGameObjectに反映させるには、
必要な情報を格納の上、_ARPlaneAnchorGameObject_を用い、
下記のように対象のGameObjectと_ARPlaneAnchor_をセットで持たせます。

```
targetGameObject.name = arPlaneAnchor.identifier;
ARPlaneAnchorGameObject arpag = new ARPlaneAnchorGameObject ();
arpag.planeAnchor = arPlaneAnchor;
arpag.gameObject = UpdatePlaneWithAnchorTransform(targetGameObject, arPlaneAnchor);
```

また、_ARPlaneAnchor_はPointCloudと違い、
連続性を持っているので下記のようにして状態を更新します。

```
UpdatePlaneWithAnchorTransform(arpag.gameobject, arPlaneAnchor);
```

なお、Unity ARKit Plugin内のサンプルでは、
_UnityARAnchorManager_というクラスで該当の処理が実装されています。

_UnityARAnchorManager_では、_UnityARUtility_に平面用の単一のprefabを持たせる実装になっており、
単一のprefabで問題ない場合は、_UnityARAnchorManager_と_UnityARUtility_を利用するのがスムーズです。




# 現実に合わせた影を表示する
影を表示するには、下記の3つの手順が必要になります。

* _UnityARCameraManagerのEnableLightEstimation_をtrueに
* Unity上に_DirectionalLight_を作成し、_UnityARAmbient_をAddComponentする
* 影のみ表示するためのMaterialとして_shadowPlaneMaterial_が用意されているので、床などに設定する

#  Unity Editor上でデバッグする
Unity ARKit Plugin内には_UnityARKitRemote_というSceneファイルがあります。
そのSceneをiPhone実機で動かすことで、Unity RemoteのようにUnity Editor上でARKitを動作させることができます。

手順としては下記となります。

1 _ARKitRemoteConnection_ プレハブをSceneに配置
2 Unity Editor上でRunを実行
3 iOS端末で_UnityARKitRemote_ Sceneの入ったアプリを開く
4 UnityのConsole、_Connected Player_から"iPhone"などを選択
5 UnityのGameウィンドウ内に"Start Remote ARKit Session"というボタンが出るのでクリック

これでiOSデバイスで映したカメラ情報およびARKit情報をUnity Editorで受け取ることができます。
映像と認識結果を連続で飛ばしていることもあり、遅延がかなり大きいのですが、ビルドに時間のかかるプロジェクトなどでは有用かと思います。



# そのほか
9/13日現在では、Unity ARKit Pluginは_Metal依存_となっているようです。

OpenGLES系で行なっていた描画処理などが動かない場合があるため、
既存のProjectをARKitに移植する際には注意が必要です。