【Unity】ARPlaneを削除する

概要

ARFoundationで作成したARPlaneを削除する方法について、あまり記事を見かけないのでまとめました。

今回作成したのは、ARKitからARPlaneを削除するネイティブコードです。

サンプル

GitHub:https://github.com/Okamochi000/ARPlaneDestroy

実証環境

  • OS:Mac
  • Unityバージョン:2020.1.17f1
  • ARFoundationバージョン:4.0.10
  • Xcodeバージョン:11.7
  • iPhone機種:iPhone SE
  • iosバージョン:13.7

サンプル操作説明

床や壁にiPhoneを向けることでARPlaneが生成されます。

ARPlaneを画面中央に映した状態で「Destroy」ボタンを押すとARPlaneが削除されます。

ARFoundationの削除機能

ARFoundationからARPlane単体を指定して削除するは探した限りではありませんでした。

DestroyでARPlaneコンポーネントの付いたオブジェクトを削除することはエラーとなり、セッションのリセットでは全てのアンカーが削除されてしまいます。

オブジェクトを非アクティブにすると見た目上消えたようにも見えますが、隠しているだけでデータ上には残っています。

ARKit上のARPlaneは元々ARAnchorの継承クラスとなります。

ARAnchorManagerにはARAnchorを削除する機能がありますが、ARFoundation上でのARPlaneとARAnchorの扱いが違うためかARAchorManagerから削除することはできませんでした。

こういった経緯からARKitのARAnchor削除を直接呼び出して削除することにしました。

ARKit上でのARPlaneの扱い

前述のとおりARKit上ではARPlaneはARAnchorの継承クラスです。

ARKitにはARSessionからARAnchorを削除する関数があるため、そこにARPlaneを指定すれば削除することが出来ます。

UnityからARKitへのデータの受け渡し

Unity公式マニュアルを参考にすると、ARKitで使用できるデータにはnativePtrがあり、

typedef struct UnityXRNativeSessionPtr
{
    int version;
    void* session;
} UnityXRNativeSessionPtr;

のような構成でできています。

Unity側から受け渡しをするときは、IntPtrで渡します。

実装サンプルコード

ARKit.mm (Objective-C)

 #import <ARKit/ARKit.h>

 extern "C" {
    typedef struct UnityXRNativeSessionPtr
    {
        int version;
        ARSession* session;
    } UnityXRNativeSessionPtr;
 
    typedef struct UnityXRNativeARPlaneAnchorPtr
    {
        int version;
        ARPlaneAnchor* anchor;
    } UnityXRNativeARPlaneAnchorPtr;
 
    void destroyARPlane(UnityXRNativeSessionPtr* sessionPtr, UnityXRNativeARPlaneAnchorPtr* arPlanePtr){
        [sessionPtr->session removeAnchor:arPlanePtr->anchor];
    }
}

DestroyButton.cs (C#)

using System;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using System.Runtime.InteropServices;

/// <summary>
/// 削除ボタン
/// </summary>
public class DestroyButton : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void destroyARPlane(IntPtr sessionPtr, IntPtr arPlanePtr);

    [SerializeField] private ARSession session = null;
    [SerializeField] private float rayDistance = 100.0f;

    /// <summary>
    /// 削除ボタン
    /// </summary>
    public void OnButtonCallback()
    {
        if (session == null)
        {
            Debug.LogError("ARSessionが設定されていません");
            return;
        }

        if (Camera.main == null)
        {
            Debug.LogError("MainCameraが設定されていません");
            return;
        }

        Transform transform = Camera.main.transform;
        RaycastHit hit;
        Physics.Raycast(transform.position, transform.forward, out hit, rayDistance);
        if (hit.transform != null)
        {
            ARPlane plane = hit.transform.GetComponent<ARPlane>();
            if (plane != null)
            {
                destroyARPlane(session.subsystem.nativePtr, plane.nativePtr);
            }
        }
    }
}
   

コメントを残す


CAPTCHA