🍊

Unity ARKitのARCoachingOverlayを表示する

2023/04/23に公開

はじめに

備忘録もかねてUnityのARKitを使用してARCoachingOverlayを表示する方法について説明したいと思います。(注意 CoachingOverlayはiOS特有の機能となります)

CoachingOverlayとは?

ARは基本的に現実をトラッキングすることが前提の技術です。トラッキングはずっと正確にできるわけではなくスマホの姿勢や周りの環境によってうまくいかない場合もあります。そのようなトラッキングの状態(厳密にいえばARSessionの状態)によってユーザーに周りの環境をカメラに映すように指示するViewのことです。
詳しい説明はApple公式の説明に任せたいと思います。
https://developer.apple.com/documentation/arkit/arcoachingoverlayview

CoachingOverlayをサポートしているかどうか

そもそもサポートしていない端末もあるので、それを調べる必要があります。(iOS特有なのでAndroidはそもそもできません)

public bool IsAROverlayCoachingSupport()
{
 return ARKitSessionSubsystem.coachingOverlaySupported;
 } 

Appleのドキュメントを見ても、iOS端末でCoachingできないという記述はなかったので(たぶん)
iOS端末であればtrueでかえってきそうな気がしています。

ARCoachingGoal

端的にいうと何をトラッキングしたいか?です。下記のドキュメントを見れば理解できると思います。
これは後ほど、ARKitSessionSubSystemのrequestedCoachingGoalプロパティに設定します。
https://docs.unity3d.com/Packages/com.unity.xr.arkit@3.0/api/UnityEngine.XR.ARKit.ARCoachingGoal.html

DefaultARKitSessionDelegate

UnityでARKitのARSessionに関わるDelegateメソッドを使用するにはARKitSessionDelegateを使用します。今回はUnity側で用意されているARKitSessionDelegateのラッパーであるDefaultARKitSessionDelegateを使用しました。ちなみに、このDelegateメソッドはCoachingOverlayを表示するのに必須ではありません。CoachingOverlayの表示状態を検知するのに必要です。
このDelegateを委任したクラスをARKitSessionSubsystemのsessionDelegateに設定します。
下記コードは表示する時と非表示になる瞬間のDelegateメソッドを実装しています。

 public class ARKitOverlayCustomDelegate : DefaultARKitSessionDelegate 
    {
    protected override void
    OnCoachingOverlayViewWillActivate(ARKitSessionSubsystem sessionSubsystem)
    {
    Debug.Log("ViewWillActivate");
    }
    protected override void
    OnCoachingOverlayViewDidDeactivate(ARKitSessionSubsystem sessionSubsystem)
    {
    Debug.Log("ViewDidDeactivate");
    }

https://docs.unity3d.com/ja/Packages/com.unity.xr.arkit@5.1/api/UnityEngine.XR.ARKit.ARKitSessionDelegate.html

var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
subsystem.sessionDelegate = new ARKitOverlayCustomDelegate();

coachingActivatesAutomatically

coachingActivatesAutomaticallyは自動でcoachingOverlayを表示するか否かです。
これはARSessionの状態によってcoachingOverlayが自動で表示されてユーザーに指示を出す場合はtrue、手動で表示させる場合はfalseになります。これも同様にARKitSessionSubsystemのcoachingActivatesAutomaticallyにセットします。

subsystem.coachingActivatesAutomatically = activesAutomatically;

実際に表示するor非表示にする。

とても簡単で、ARKitSessionSubsystemのSetCoachingActiveにtrueやfalseを設定するだけです。ARCoachingOverlayTransitionにはAnimatedの他にInstantが存在し、アニメーションして表示するか即表示させるかの違いです。

public void ShowOverlay()
{
var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
subsystem.SetCoachingActive(true, ARCoachingOverlayTransition.Animated);
}
public void HideOverlay()
{
var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
subsystem.SetCoachingActive(false, ARCoachingOverlayTransition.Animated);
}

サンプルコード
(個人で作成しているARアプリのコードをそのまま乗っけているのでUniRxやDebugなど少し余計なものがありますmm)

using DefaultNamespace;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARKit;
using UniRx;

#if UNITY_IOS

public class ARCoachingOverlayView : MonoBehaviour 
{
    [SerializeField] private bool activesAutomatically = true;
    [SerializeField] private ARCoachingGoal goal = ARCoachingGoal.Tracking;
    public Subject<Unit> lifeCycleEnable = new Subject<Unit>();
    public Subject<Unit> lifeCycleDisable = new Subject<Unit>();
    private void OnEnable()
    {
        "OnEable!!".DebugBlue();
        lifeCycleEnable.OnNext(Unit.Default);
    }

    public void EnableOverlay()
    {
        "enable overlay".DebugBlue();
        var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
        subsystem.requestedCoachingGoal = goal;
        subsystem.coachingActivatesAutomatically = activesAutomatically;
        subsystem.sessionDelegate = new ARKitOverlayCustomDelegate();
    }

    public void ShowOverlay()
    {
        var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
        subsystem.SetCoachingActive(true, ARCoachingOverlayTransition.Animated);
        "show Overlay".DebugOrange();
    }
    
    public void HideOverlay()
    {
        var subsystem = (ARKitSessionSubsystem) GetComponent<ARSession>().subsystem;
        subsystem.SetCoachingActive(false, ARCoachingOverlayTransition.Animated);
        "hide Overlay".DebugBlue();
    }

    public void ShownotSupportOverlayView()
    {
       "ARCoachingOverlayView is not supported by this device.".DebugCyan(); 
    }

    private void OnDisable()
    {
        "OnDisable!!".DebugBlue();
        lifeCycleDisable.OnNext(Unit.Default);
    }


    private void OnDestroy()
    {
        lifeCycleEnable.Dispose();
        lifeCycleDisable.Dispose();
    }
    
}
#endif

Discussion