Table of Contents

session 실행 결과 가져오기

session 실행 중에는 씬의 일부 오브젝트 transform과 카메라 이미지가 변경됩니다. 때로는 이러한 변경만으로는 앱 요구를 충족하지 못해, session의 각 frame 실행 결과를 가져와 추가로 처리해야 할 수 있습니다. 이 문서는 이러한 결과 데이터를 가져오고 사용하는 방법을 설명합니다.

시작하기 전에

InputFrame 업데이트 가져오기

InputFrameUpdate 이벤트를 사용해 InputFrame 업데이트를 가져올 수 있습니다. 이 이벤트는 session의 각 frame 출력 데이터에서 InputFrame이 변경될 때만 발생합니다.

참고

InputFrameUpdate는 EasyAR가 화면을 그리는 session에서만 유효합니다. 일반적으로 AR Foundation이나 헤드셋을 사용할 때는 유효하지 않으며, 이 경우 해당 서드파티 라이브러리가 제공하는 방법으로 데이터 업데이트를 가져와야 합니다.

InputFrame을 사용하면 물리 카메라 이미지, 카메라 파라미터, 타임스탬프, 월드 좌표계에 대한 물리 카메라 transform, 추적 상태 등을 가져올 수 있습니다. 다만 카메라 transform은 이미 session에 의해 가상 카메라와 다른 오브젝트에 적용되므로, 보통은 InputFrame으로 카메라 transform을 가져올 필요가 없습니다.

현재 frame의 물리 카메라 이미지 가져오기

InputFrame.image() 메서드를 사용해 Image 타입의 물리 카메라 이미지 데이터를 가져올 수 있습니다.

예를 들어 다음 코드는 InputFrame이 업데이트될 때 물리 카메라 이미지를 가져옵니다.

Session.InputFrameUpdate += (inputFrame) => {
    using (var image = inputFrame.image())
    {
    }
};
주의

Image 타입 데이터와 그로부터 얻은 다른 class 타입 데이터를 사용할 때는 Dispose()가 올바르게 호출되도록 해야 합니다(위 코드의 using 문이 이를 보장합니다). 그렇지 않으면 메모리 누수나 화면 업데이트 중단이 발생할 수 있습니다.

InputFrame 또는 Image를 다음 frame까지 유지해 사용해야 한다면, 유지할 데이터 양에 맞춰 ARAssembly.ExtraBufferCapacity 값을 늘려야 합니다. 그렇지 않으면 버퍼 부족으로 데이터 가져오기가 실패할 수 있습니다.

InputFrame을 유지하려면 Clone()으로 참조 복사본을 만든 뒤, 더 이상 필요 없을 때 복사본에 대해 Dispose()를 호출해야 합니다.

물리 카메라의 frame rate는 일반적으로 렌더링 frame rate보다 낮기 때문에, 모든 렌더링 frame에서 InputFrameUpdate 이벤트를 받는 것은 아닙니다. 하지만 물리 카메라 화면도 모든 렌더링 frame마다 업데이트되지는 않습니다. 다음 InputFrameUpdate 이벤트가 발생하기 전까지의 모든 렌더링 frame 내용은 현재 InputFrame의 이미지와 같습니다.

참고

InputFrame의 이미지는 현재 frame의 가상 카메라 배경 화면과 반드시 일치하지만, 배경 렌더링 시 확대/축소와 크롭이 있을 수 있으므로 가져온 이미지 크기나 비율이 화면 표시와 다르게 보이는 것은 정상입니다.

또한 InputFrame.image()가 반환하는 이미지 데이터는 CPU에서 읽을 수 있는 데이터이며 GPU texture가 아닙니다. GPU에서 이미지 데이터를 사용해야 한다면 데이터를 GPU texture로 업로드하거나, CameraImageRenderer.RequestTargetTexture(Action<Camera, RenderTexture>) 인터페이스를 통해 GPU texture를 직접 가져와야 합니다.

[선택 사항] 물리 카메라 이미지 렌더링 가로채기

ARAssembly.CameraImageRenderer를 사용해 물리 카메라 이미지 렌더링을 제어할 수 있습니다.

다음 코드는 물리 카메라 이미지 렌더링을 중지합니다.

if (Session.Assembly != null && Session.Assembly.CameraImageRenderer.OnSome)
{
    Session.Assembly.CameraImageRenderer.Value.enabled = false;
}

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

참고

EasyAR가 화면을 그리는 session에서만 위 방법으로 화면 업데이트를 중지할 수 있습니다. 일반적으로 AR Foundation이나 헤드셋을 사용할 때는 유효하지 않으며, 이 경우 해당 서드파티 라이브러리가 제공하는 방법으로 같은 기능을 구현해야 합니다.

물리 카메라 이미지 렌더링을 중지한 뒤에는 애플리케이션이 InputFrame을 통해 물리 카메라 이미지 데이터를 가져와 사용자 정의 렌더링에 사용할 수 있습니다.

transform 업데이트 가져오기

PostSessionUpdate 이벤트를 통해 session이 매번 업데이트된 뒤 씬 오브젝트의 transform 데이터를 가져올 수 있습니다.

참고

Mega 같은 일부 기능은 이미지가 바뀌지 않고 서비스 업데이트 요청이 표시되지 않아도 AR 계산이 매 렌더링 frame마다 실행됩니다. 따라서 모든 transform 변화를 가져와야 한다면 일부 frame만이 아니라 매 frame마다 transform 데이터를 가져와야 합니다.

가상 카메라의 transform 가져오기

ARAssembly.Camera를 통해 씬의 카메라 transform을 가져올 수 있습니다.

Session.PostSessionUpdate += () =>
{
    var position = Session.Assembly.Camera.transform.position;
    var rotation = Session.Assembly.Camera.transform.rotation;
};

target의 transform 가져오기

사용 중인 구체적인 target 오브젝트를 통해 씬의 target transform을 가져올 수 있습니다. 예를 들어 image tracking에서는 그 target이 ImageTargetController 컴포넌트가 붙은 오브젝트입니다.

Session.PostSessionUpdate += () =>
{
    var position = target.transform.position;
    var rotation = target.transform.rotation;
};

[선택 사항] pose 가져오기

pose는 오브젝트의 위치와 방향을 설명하는 데이터 구조로, 보통 position과 rotation 두 부분으로 구성됩니다. AR 앱에서는 pose가 물리 카메라나 추적 target의 위치와 방향을 어떤 기준 좌표계에 대해 설명할 때 주로 사용됩니다.

Unity는 원시 pose 데이터를 제공하지 않습니다. pose는 보통 씬 오브젝트의 이동을 구동하는 데 쓰이는데, 그 일은 바로 session이 자동으로 수행하기 때문입니다. 콘텐츠 계산과 렌더링에는 transform만으로 충분합니다.

중요

아래 방법을 읽기 전에, 씬의 카메라, 추적 target 등 오브젝트의 transform 데이터가 이미 요구 사항을 충족하는지 다시 생각해 보세요. 보통 추가 pose 데이터는 필요하지 않습니다.

정말 어떤 이유로든 pose 데이터가 필요하다면 PostSessionUpdate 이벤트에서 transform을 통해 원하는 pose 값을 계산할 수 있습니다. 일반적으로 PostSessionUpdate에서 얻는 target과 camera의 상대 transform이 곧 pose입니다.

다음 코드는 camera와 target의 transform을 얻고 둘 사이의 상대 pose를 계산하는 방법을 보여 줍니다.

Session.PostSessionUpdate += () =>
{
    Pose cameraToWorld = new(Session.Assembly.Camera.transform.position, Session.Assembly.Camera.transform.rotation);
    Pose targetToWorld = new(target.transform.position, target.transform.rotation);
    Pose worldToTarget = new()
    {
        position = Quaternion.Inverse(targetToWorld.rotation) * (-targetToWorld.position),
        rotation = Quaternion.Inverse(targetToWorld.rotation)
    };
    Pose cameraToTarget = cameraToWorld.GetTransformedBy(worldToTarget);
};
주의

AR Foundation, 헤드셋 또는 다른 서드파티 라이브러리를 함께 사용하고 있다면, 그 라이브러리들도 씬의 카메라 transform을 수정할 수 있습니다. 관련 pose 계산은 해당 라이브러리의 업데이트 로직이 끝난 뒤에 수행해야 하며, 그렇지 않으면 결과가 올바르지 않을 수 있습니다. 이런 상황에서도 PostSessionUpdate에서 target과 origin의 상대 pose는 정확합니다.

[선택 사항] transform 업데이트 가로채기

AR 기능이 실행 중일 때 Unity의 카메라, 추적 target 등의 오브젝트 transform은 보통 session에 의해 자동으로 업데이트됩니다. 이러한 업데이트는 AR 렌더링의 정확성과 일관성을 보장하므로, 직접 가로채는 방법은 없습니다.

하지만 오브젝트의 transform 업데이트 로직을 사용자 정의해야 한다면 PostSessionUpdate 이벤트를 감시하여 구현할 수 있습니다. 여기에는 조금 번거로운 방법이 필요합니다.

  1. 일반적으로 렌더링 콘텐츠는 session이 제어하는 오브젝트 아래의 자식 노드나 부가 컴포넌트 형태로 붙여야 하지만, 오브젝트 transform을 사용자 정의로 업데이트해야 한다면 그 오브젝트를 session 제어 계층에서 분리해야 합니다. 즉, session이 제어하는 오브젝트의 자식 노드가 되어서는 안 됩니다.
  2. PostSessionUpdate 이벤트에서 사용자 정의로 업데이트할 오브젝트의 transform을 기록합니다.
  3. 마지막으로 PostSessionUpdate 이벤트에서 session이 제공하는 데이터를 바탕으로 사용자 정의 로직으로 해당 오브젝트의 transform을 업데이트합니다.
참고

PostSessionUpdate 이벤트를 사용하는 것이 필수입니다. 그 시점 이후에야 session이 씬 오브젝트를 더 이상 조작하지 않기 때문입니다.

이 방법은 camera 수정에는 사용할 수 없으며, 카메라의 사용자 정의 업데이트를 처리하려면 더 복잡한 로직이 필요합니다.

또한 이 방법은 오브젝트 transform을 사용자 정의로 업데이트하는 용도일 뿐, session이 제어하는 오브젝트의 transform을 수정하는 데는 사용할 수 없습니다. session이 제어하는 오브젝트의 transform이 외부에서 수정되더라도 session은 다음 frame 업데이트에서 그 변경을 덮어쓰며, 이는 일부 계산의 정확성에 영향을 줄 수 있습니다.

주의

이 방법을 사용할 때는 오브젝트 transform의 정확성을 보장해야 하며, 그렇지 않으면 AR 렌더링 오류가 발생할 수 있습니다.

AR Foundation, 헤드셋 또는 다른 서드파티 라이브러리를 함께 사용한다면, 그 라이브러리들이 씬 오브젝트의 transform을 수정할 수 있습니다. 해당 라이브러리의 업데이트 로직과 사용자 정의 로직이 충돌하지 않도록 해야 하며, 그렇지 않으면 예기치 않은 결과가 발생할 수 있습니다.

관련 주제