AR Foundation Android 앱에서 Depth 사용

Depth API를 사용하면 기기의 카메라가 장면에 있는 실제 객체의 크기와 모양을 파악할 수 있습니다. 카메라를 사용하여 깊이 이미지 또는 깊이 지도를 만들어 앱에 AR의 사실감을 더합니다. 깊이 이미지로 제공되는 정보를 사용하여 가상 객체가 실제 객체 앞이나 뒤에 정확하게 표시되도록 하여 몰입도 높고 사실적인 사용자 환경을 만들 수 있습니다.

심도 정보는 움직임을 통해 계산되며, 가능한 경우 ToF (Time-Of-ToF) 센서와 같은 하드웨어 깊이 센서의 정보와 결합될 수 있습니다. Depth API를 지원하기 위해 기기에 ToF 센서가 필요하지 않음.

기본 요건

계속 진행하기 전에 기본 AR 개념ARCore 세션 구성 방법을 이해해야 합니다.

앱을 Depth Required 또는 Depth Optional로 구성 (Android만 해당)

AR 환경의 핵심 부분이 깊이에 의존하거나 깊이를 사용하는 앱 부분에 적절한 대체가 없기 때문에 앱에 Depth API 지원이 필요한 경우 Google Play 스토어의 앱 배포를 Depth API를 지원하는 기기로 제한할 수 있습니다.

Depth Required 앱 만들기

Edit > Project Settings > XR Plug-in Management > ARCore로 이동합니다.

Depth는 기본적으로 Required로 설정됩니다.

Depth Optional 앱 만들기

  1. Edit > Project Settings > XR Plug-in Management > ARCore로 이동합니다.

  2. Depth 드롭다운 메뉴에서 Optional를 선택하여 앱을 깊이 선택사항으로 설정합니다.

깊이 사용 설정

리소스를 절약하기 위해 ARCore는 기본적으로 Depth API를 사용 설정하지 않습니다. 지원되는 기기에서 깊이를 활용하려면 CameraARCameraBackground 구성요소를 사용하여 AROcclusionManager 구성요소를 AR 카메라 게임 객체에 수동으로 추가해야 합니다. 자세한 내용은 Unity 문서의 자동 오클루전을 참고하세요.

새 ARCore 세션에서 다음과 같이 사용자 기기가 깊이와 Depth API를 지원하는지 확인합니다.

// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …

// Check whether the user's device supports the Depth API.
if (occlusionManager.descriptor?.supportsEnvironmentDepthImage)
{
    // If depth mode is available on the user's device, perform
    // the steps you want here.
}

깊이 이미지 획득

AROcclusionManager에서 최신 환경 심도 이미지를 가져옵니다.

// Reference to AROcclusionManager that should be added to the AR Camera
// game object that contains the Camera and ARCameraBackground components.
var occlusionManager = …

if (occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
{
    using (image)
    {
        // Use the texture.
    }
}

유연성을 높이기 위해 원시 CPU 이미지를 RawImage로 변환할 수 있습니다. 이 방법에 관한 예는 Unity의 ARFoundation 샘플에서 확인할 수 있습니다.

깊이 값 이해

관찰된 실제 도형에 있는 점 A과 깊이 이미지의 같은 지점을 나타내는 2D 점 a이 있으면 a의 Depth API에서 지정된 값은 주축에 투영된 CA의 길이와 같습니다. 카메라 원점(C)을 기준으로 한 A의 z 좌표라고도 합니다. Depth API를 사용할 때는 깊이 값이 광선 CA 자체의 길이가 아니라 광선의 투영임을 이해하는 것이 중요합니다.

가상 객체를 제외하고 깊이 데이터 시각화

깊이 데이터에 관한 대략적인 개요와 가상 이미지를 가리는 데 사용하는 방법은 Unity의 블로그 게시물을 확인하세요. 또한 Unity의 ARFoundation 샘플에서는 가상 이미지를 가리고 깊이 데이터를 시각화하는 방법을 보여줍니다.

2 패스 렌더링 또는 객체별 정방향 전달 렌더링을 사용하여 오클루전을 렌더링할 수 있습니다. 각 접근 방식의 효율성은 장면의 복잡성과 기타 앱 관련 고려사항에 따라 다릅니다.

객체별, 정방향 전달 렌더링

객체별 정방향 전달 렌더링은 머티리얼 셰이더에서 객체의 각 픽셀의 오클루전을 결정합니다. 픽셀이 보이지 않으면 일반적으로 알파 블렌딩을 통해 잘리므로 사용자 기기에서 오클루전을 시뮬레이션합니다.

2 패스 렌더링

투 패스 렌더링을 사용하면 첫 번째 패스가 모든 가상 콘텐츠를 중간 버퍼로 렌더링합니다. 두 번째 패스는 실제 깊이와 가상 장면 깊이의 차이에 따라 가상 장면을 배경에 블렌딩합니다. 이 접근 방식은 객체별 추가 셰이더 작업이 필요하지 않으며 일반적으로 정방향 전달 메서드보다 더 균일한 결과를 생성합니다.

깊이 이미지에서 거리 추출

가상 객체를 가리거나 깊이 데이터를 시각화하는 것 이외의 목적으로 Depth API를 사용하려면 깊이 이미지에서 정보를 추출하세요.

Texture2D _depthTexture;
short[] _depthArray;

void UpdateEnvironmentDepthImage()
{
  if (_occlusionManager &&
        _occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
    {
        using (image)
        {
            UpdateRawImage(ref _depthTexture, image, TextureFormat.R16);
            _depthWidth = image.width;
            _depthHeight = image.height;
        }
    }
  var byteBuffer = _depthTexture.GetRawTextureData();
  Buffer.BlockCopy(byteBuffer, 0, _depthArray, 0, byteBuffer.Length);
}

// Obtain the depth value in meters at a normalized screen point.
public static float GetDepthFromUV(Vector2 uv, short[] depthArray)
{
    int depthX = (int)(uv.x * (DepthWidth - 1));
    int depthY = (int)(uv.y * (DepthHeight - 1));

    return GetDepthFromXY(depthX, depthY, depthArray);
}

// Obtain the depth value in meters at the specified x, y location.
public static float GetDepthFromXY(int x, int y, short[] depthArray)
{
    if (!Initialized)
    {
        return InvalidDepthValue;
    }

    if (x >= DepthWidth || x < 0 || y >= DepthHeight || y < 0)
    {
        return InvalidDepthValue;
    }

    var depthIndex = (y * DepthWidth) + x;
    var depthInShort = depthArray[depthIndex];
    var depthInMeters = depthInShort * MillimeterToMeter;
    return depthInMeters;
}

다음 단계

  • Raw Depth API를 사용하여 더 정확하게 감지할 수 있습니다.
  • 깊이 데이터에 액세스하는 다양한 방법을 보여주는 ARCore Depth Lab을 확인하세요.