【Unity】ARKitでセッション情報を破棄する

UnityでARKitを使用する際、特に凝ったことをしないのであればHelpersにあるUnityARCameraManager.csによってセッションの管理をする形になるかと思います。
ただ、このコンポーネントを使用すると、たとえばシーン遷移によって再度トラッキングをし直したいというとき、前のセッションの情報が残ってしまいます。

というわけで、これの解決法を調べてみます。

まず、これで何が困るかと言うと、同じくHelpersにあるUnityARGeneratePlane.csを利用している際に、前のセッションで生成されたplaneが表示されないままになります。

そもそもどうやってplaneが生成されるかというと、UnityARGeneratePlaneが生成しているUnityARAnchorManagerがUnityARSessionNativeInterfaceのARAnchorAddedEventイベント発生時に同クラスのAddAnchorメソッドを実行することで生成されています。

UnityARSessionNativeInterface.ARAnchorAddedEvent += AddAnchor;

が、UnityARGeneratePlaneがシーン遷移などによってOnDestroyのタイミングでplaneのGameObjectを破棄し、再度UnityARCameraManagerを利用しているシーンに遷移してきたとき、セッションはAnchorを維持しているためARAnchorAddedEventは発火しないので、planeが再生成されない、ということになります。(たぶん)

というわけでどうしたらよいかというと、UnityARCameraManager.csの以下の部分に注目します。

m_session = UnityARSessionNativeInterface.GetARSessionNativeInterface();
(略)
ARKitWorldTrackingSessionConfiguration config = new ARKitWorldTrackingSessionConfiguration();
config.planeDetection = planeDetection;
config.alignment = startAlignment;
config.getPointCloudData = getPointCloud;
config.enableLightEstimation = enableLightEstimation;
m_session.RunWithConfig(config);

どうやらここでセッションのconfigを設定しているようです。

GetARSessionNativeInterfaceはARKitWorldTrackingSessionConfigurationの他、UnityARSessionRunOptionも指定することができます。
具体的には以下。
ARSession.RunOptions - ARSession | Apple Developer Documentation
どうやらデバイスの位置もアンカーもリセットすることができそうです。

というわけでUnityARCameraManager.csを以下のように書き換えてみます。

m_session = UnityARSessionNativeInterface.GetARSessionNativeInterface();
(略)
ARKitWorldTrackingSessionConfiguration config = new ARKitWorldTrackingSessionConfiguration ();
config.planeDetection = planeDetection;
config.alignment = startAlignment;
config.getPointCloudData = getPointCloud;
config.enableLightEstimation = enableLightEstimation;
var option = UnityARSessionRunOption.ARSessionRunOptionRemoveExistingAnchors | UnityARSessionRunOption.ARSessionRunOptionResetTracking;
m_session.RunWithConfigAndOptions (config, option);

これでSnapCameraARManagerがスタートする度にデバイスの位置もアンカーもリセットされ、planeも再生成されるようになりました。
めでたしめでたし。

2017.11.24追記
これだけだと作りによってはUnityARAnchorManagerによって登録されたUnityARSessionNativeInterface.ARAnchorAddedEventの購読が解除されなくて無駄にplaneが生成される可能性があるので、UnityARAnchorManagerのDestroyメソッドを以下のようにしてやるとより安心感があります。

public void Destroy ()
{
    UnityARSessionNativeInterface.ARAnchorAddedEvent -= AddAnchor;
    UnityARSessionNativeInterface.ARAnchorUpdatedEvent -= UpdateAnchor;
    UnityARSessionNativeInterface.ARAnchorRemovedEvent -= RemoveAnchor;
    foreach (ARPlaneAnchorGameObject arpag in GetCurrentPlaneAnchors()) {
        GameObject.Destroy (arpag.gameObject);
    }

    planeAnchorMap.Clear ();
}

スポンサーリンク