Table of Contents

세션 내 AR 기능 컴포넌트에 접근하기

실행 중인 세션에서는 Assembly 속성을 통해 각 기능 컴포넌트에 접근할 수 있습니다. 이 문서는 이러한 컴포넌트에 접근하는 방법과 접근 시 주의할 점을 설명합니다.

시작하기 전에

편집 시 또는 시작 전에 AR 컴포넌트 설정하기

때로는 DesiredFocusMode 같은 일부 컴포넌트 옵션을 컴포넌트 시작 전에 설정해야 합니다. 세션 시작 후에 직접 설정하고 시작하고 싶지 않다면, 간단한 방법은 세션 어셈블리 전에 사용할 가능성이 있는 모든 frame source 컴포넌트를 미리 설정해 두는 것입니다. 어셈블리 과정은 이 컴포넌트들 중 하나 이상을 유지하고 해당 설정을 적용합니다.

이때는 FindAnyObjectByType<T>()이나 GetComponent<T>() 같은 일반적인 Unity 메서드로 컴포넌트를 찾은 뒤 설정할 수 있습니다.

참고

이렇게 가져온 AR 컴포넌트가 런타임에 세션에 포함될지는 확실하지 않습니다. 따라서 가능한 모든 경우를 대비해 설정해야 합니다.

예를 들어, 아래 코드는 세션 어셈블리 전에 모든 frame source 컴포넌트의 초점 모드를 변경하는 과정을 보여줍니다.

void Awake()
{
    var allFrameSources = Session.GetComponentsInChildren<FrameSource>();
    foreach (var source in allFrameSources)
    {
        if (source is CameraDeviceFrameSource)
        {
            ((CameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? CameraDeviceFocusMode.Continousauto : CameraDeviceFocusMode.Medium;
        }
        else if (source is MotionTrackerFrameSource)
        {
            ((MotionTrackerFrameSource)source).DesiredFocusMode = autoFocus ? MotionTrackerCameraDeviceFocusMode.Continousauto : MotionTrackerCameraDeviceFocusMode.Medium;
        }
        else if (source is ARCoreFrameSource)
        {
            ((ARCoreFrameSource)source).DesiredFocusMode = autoFocus ? ARCoreCameraDeviceFocusMode.Auto : ARCoreCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARKitFrameSource)
        {
            ((ARKitFrameSource)source).DesiredFocusMode = autoFocus ? ARKitCameraDeviceFocusMode.Auto : ARKitCameraDeviceFocusMode.Fixed;
        }
        else if (source is AREngineFrameSource)
        {
            ((AREngineFrameSource)source).DesiredFocusMode = autoFocus ? AREngineCameraDeviceFocusMode.Auto : AREngineCameraDeviceFocusMode.Fixed;
        }
        else if (source is ThreeDofCameraDeviceFrameSource)
        {
            ((ThreeDofCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? ThreeDofCameraDeviceFocusMode.Auto : ThreeDofCameraDeviceFocusMode.Fixed;
        }
        else if (source is InertialCameraDeviceFrameSource)
        {
            ((InertialCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? InertialCameraDeviceFocusMode.Auto : InertialCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARFoundationFrameSource)
        {
            cameraManager.autoFocusRequested = autoFocus;
        }
    }
}

위 과정은 편집기에서도 수행할 수 있으며, 이 경우에도 모든 컴포넌트를 대상으로 설정해야 합니다.

alt text

여기서 ARCoreARFoundationFrameSourceARKitARFoundationFrameSource 두 frame source에 해당하는 설정은 Main Camera의 컴포넌트에서 지정합니다.

경고

이런 방식으로 가져온 AR 컴포넌트는 실행 전에만 사용할 수 있습니다.
어셈블리 과정에서 AR 컴포넌트를 선별하므로, 씬 트리에서 가져온 AR 컴포넌트가 실제로 세션에 포함되지 않을 수도 있고, 이 경우 정상적으로 동작하지 않습니다.

실행 중 조립된 AR 컴포넌트 사용하기

세션에서 실행되는 AR 컴포넌트는 어셈블리 후에야 결정됩니다. 어셈블리가 완료되기 전에는 어떤 AR 컴포넌트도 사용할 수 없습니다. 조립된 AR 컴포넌트는 Assembly 속성을 통해 접근할 수 있습니다.

Assembly는 세션 상태가 Assembled 이상일 때 사용할 수 있습니다. 자세히 말하면, Assemble() 메서드가 끝난 뒤에야 Assembly 속성에 값이 들어가며, 이를 통해 세션 컴포넌트에 접근할 수 있습니다. 세션이 중지되거나 손상되면 Assembly 속성은 비워져 더 이상 컴포넌트에 접근할 수 없습니다.

스크립트에서 세션의 State를 확인하면 현재 AR 컴포넌트에 접근할 수 있는지 판단할 수 있습니다.

if (Session.State >= ARSession.SessionState.Ready)
{
    // Assembly를 사용할 수 있습니다
}
else
{
    // Assembly를 사용할 수 없습니다
}

StateChanged 이벤트를 구독하여 세션 상태 변화를 받으면 적절한 시점에 AR 컴포넌트에 접근할 수도 있습니다. 일반적으로 Ready 상태를 포착하려면 세션 시작 전에 StateChanged 이벤트를 구독해야 하며, 보통 Awake()에서 구독하는 것이 안전합니다.

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (Session.State == ARSession.SessionState.Ready)
        {
            // Assembly를 사용할 수 있습니다. 이후 session이 중지되거나 손상될 때까지 Assembly에 계속 접근할 수 있습니다
        }
        else if (Session.State < ARSession.SessionState.Ready)
        {
            // Assembly를 사용할 수 없습니다. 이후 session이 다시 시작될 때까지 Assembly에 접근할 수 없습니다
        }
        else
        {
            // Assembly를 사용할 수 있습니다. 일반적으로 처리할 필요가 없습니다
        }
    };
}
주의

FindAnyObjectByType<T>()이나 GetComponent<T>() 같은 방법으로 가져온 AR 컴포넌트가 반드시 세션에 포함될 것이 확실하다면, 런타임에서도 사용할 수 있습니다.
이 경우 컴포넌트 참조를 저장하는 것은 안전하지만, 사용할 때는 세션이 실행 중이고 해당 컴포넌트가 세션에 올바르게 포함되어 있어야 합니다. 그렇지 않으면 예외나 예기치 않은 동작이 발생할 수 있습니다.
세션 시작 전과 중지 후에는 이러한 컴포넌트를 사용할 수 없습니다. 이런 방식으로 사용하더라도 세션의 StateStateChanged 이벤트를 함께 확인하는 것이 좋습니다.

frame source 컴포넌트 접근하기

ARAssembly.FrameSource 속성을 사용해 frame source 컴포넌트에 접근할 수 있습니다. 정상적으로 실행 중인 세션에서는 ARAssembly.FrameSource가 하나만 존재합니다.

세션을 사용할 때는 보통 ARAssembly.FrameSource에 접근해야 런타임에서 실제로 사용 중인 frame source 컴포넌트 유형을 확인할 수 있으며, 그에 따라 해당 컴포넌트 전용 속성과 메서드에 접근할 수 있습니다.

예를 들어, 아래 코드는 frame source에 따라 서로 다른 평면 검출 방법을 사용하는 방법을 보여줍니다.

void PlaceObject(Vector2 touchPosition)
{
    if (Session.Assembly.FrameSource is MotionTrackerFrameSource)
    {
        Ray ray = Session.Assembly.Camera.ScreenPointToRay(touchPosition);
        if (Physics.Raycast(ray, out var hitInfo))
        {
            TouchRoot.transform.position = hitInfo.point;
        }
    }
    else if (Session.Assembly.FrameSource is ARFoundationFrameSource)
    {
        var raycastManager = Session.Assembly.Origin.Value.GetComponent<UnityEngine.XR.ARFoundation.ARRaycastManager>();
        var hits = new List<UnityEngine.XR.ARFoundation.ARRaycastHit>();
        if (raycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinPolygon))
        {
            var hitPose = hits[0].pose;
            TouchRoot.transform.position = hitPose.position;
        }
    }
}

frame filter 컴포넌트 접근하기

ARAssembly.FrameFilters 속성을 사용해 frame filter 컴포넌트에 접근할 수 있습니다. 정상적으로 실행 중인 세션에서는 ARAssembly.FrameFilters 목록에 같은 유형의 컴포넌트가 여러 개 있을 수도 있습니다.

예를 들어, 아래 코드는 세션에서 MegaTrackerFrameFilter 하나를 가져와 해당 이벤트를 등록하는 방법을 보여줍니다.

var megaTracker = session.Assembly.FrameFilters.Where(f => f is MegaTrackerFrameFilter).FirstOrDefault() as MegaTrackerFrameFilter;
if (megaTracker)
{
    megaTracker.LocalizationRespond += (response) =>
    {
    };
}

camera 컴포넌트 접근하기

ARAssembly.Camera 속성을 사용해 camera 컴포넌트에 접근할 수 있습니다. 씬에 카메라가 여러 개 있을 때는 AR에서 사용하는 카메라를 빠르게 찾는 방법이 됩니다.

예를 들어, 아래 코드는 세션의 camera를 가져와 씬의 오브젝트를 대상으로 레이캐스트하는 방법을 보여줍니다.

var ray = Session.Assembly.Camera.ScreenPointToRay(screenPoint);
if (Physics.Raycast(ray, out var hitInfo))
{
    TouchRoot.transform.position = hitInfo.point;
};

origin 컴포넌트 접근하기

ARAssembly.Origin 속성을 사용해 origin 컴포넌트에 접근할 수 있습니다.

예를 들어, 아래 코드는 세션의 origin을 가져와 현재 카메라 위치와 방향을 나타내는 원뿔을 씬에 표시하는 방법을 보여줍니다.

if (session.Assembly.Origin.OnSome)
{
    GameObject frustum = Instantiate(CameraFrustumPrefab, session.Assembly.Camera.transform.position, session.Assembly.Camera.transform.rotation);
    frustum.transform.SetParent(session.Assembly.Origin.Value.transform);
}

여기서는 먼저 ARAssembly.Origin이 존재하는지 확인해야 합니다.

참고

ARAssembly.Origin은 모션 추적 기능이 활성화된 세션에서만 존재합니다.

CameraImageRenderer 컴포넌트 접근하기

ARAssembly.CameraImageRenderer 속성을 사용해 CameraImageRenderer 컴포넌트에 접근할 수 있습니다.

예를 들어, 아래 코드는 물리 카메라 이미지의 RenderTexture를 가져옵니다.

RenderTexture renderTexture;

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (state == ARSession.SessionState.Ready && Session.Assembly.CameraImageRenderer.OnSome)
        {
            Session.Assembly.CameraImageRenderer.Value.RequestTargetTexture((_, texture) => renderTexture = texture);
        }
    };
}

여기서도 먼저 ARAssembly.CameraImageRenderer가 존재하는지 확인해야 합니다.

참고

ARAssembly.CameraImageRenderer는 EasyAR이 화면을 그리는 세션에서만 유효합니다. 일반적으로 AR Foundation이나 헤드셋을 사용할 때는 유효하지 않으며, 이 경우 물리 카메라 화면의 렌더링은 AR Foundation 또는 헤드셋 SDK가 담당합니다.

FrameRecorder 컴포넌트 접근하기

ARAssembly.FrameRecorder 속성을 사용해 FrameRecorder 컴포넌트에 접근할 수 있습니다.

예를 들어, 아래 코드는 녹화를 시작하며, 파일 저장 위치는 설정에 따라 달라집니다. 기본값은 앱 저장 디렉터리입니다.

if (session.Assembly.FrameRecorder.OnSome)
{
    var frameRecorder = session.Assembly.FrameRecorder.Value;
    frameRecorder.enabled = true;
}

여기서도 먼저 ARAssembly.FrameRecorder가 존재하는지 확인해야 합니다.

참고

ARAssembly.FrameRecorderFramePlayer를 사용하는 경우처럼 일부 상황에서는 사용할 수 없습니다.

후속 단계

관련 주제