概要
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);
}
}
}
}
投稿者プロフィール
最新の投稿
- 2023年10月9日プログラミング【ライセンス】GPL/LGPLライブラリについて
- 2023年8月19日その他【Pixiv】閲覧注意機能が反映されないときに確認すること
- 2023年4月30日プログラミング【JavaScript】ファイルの保存先をダイアログで指定する方法 – showSaveFilePicker()の使い方
- 2022年10月17日その他「NovelAI Diffusion」を使ってみた (Img2Img)