Używanie głębi w aplikacji AR Foundation na Androida

Interfejs Depth API ułatwia aparatowi urządzenia określenie rozmiaru i kształtu rzeczywistych obiektów na ekranie. Aparat wykorzystuje aparat do tworzenia zdjęć głębi (map głębi), dzięki czemu aplikacja nabiera warstwy realizmu AR. Za pomocą informacji dostarczanych przez zdjęcia w trybie głębokim możesz tworzyć wirtualne obiekty dokładnie przed lub za rzeczywistymi obiektami, co sprawia, że wrażenia użytkownika są wciągające i realistyczne.

Informacje o głębokości są obliczane na podstawie ruchu i mogą być łączone z informacjami pochodzącymi ze sprzętowego czujnika głębokości, takiego jak czujnik czasu lotu (ToF), jeśli jest dostępny. Urządzenie nie potrzebuje czujnika ToF, aby obsługiwać interfejs Depth API.

Wymagania wstępne

Zanim przejdziesz dalej, upewnij się, że znasz podstawowe pojęcia związane z AR i wiesz, jak skonfigurować sesję ARCore.

Skonfiguruj aplikację jako Depth Required lub Depth Optional (tylko Android)

Jeśli Twoja aplikacja wymaga obsługi interfejsu Depth API, ponieważ główna część AR zależy od głębi lub nie działa w przypadku określonych części aplikacji obsługujących głębię, możesz ograniczyć jej rozpowszechnianie w Sklepie Google Play do urządzeń, które obsługują interfejs Depth API.

Zmień ustawienia aplikacji na Depth Required

Wejdź na Edit > Project Settings > XR Plug-in Management > ARCore.

Depth ma domyślnie wartość Required.

Zmień ustawienia aplikacji na Depth Optional

  1. Wejdź na Edit > Project Settings > XR Plug-in Management > ARCore.

  2. Z menu Depth wybierz Optional, aby dla aplikacji ustawić opcjonalną głębokość.

Włącz głębię

Aby oszczędzać zasoby, ARCore domyślnie nie włącza interfejsu Depth API. Aby korzystać z funkcji głębi na obsługiwanych urządzeniach, musisz ręcznie dodać komponent AROcclusionManager do obiektu gry Kamera AR za pomocą komponentów Camera i ARCameraBackground. Więcej informacji znajdziesz w sekcji Automatyczne przesłonięcie w dokumentacji Unity.

W nowej sesji ARCore sprawdź, czy urządzenie użytkownika obsługuje funkcje głębi i interfejsu 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.
}

Pobierz zdjęcia głębi

Pobierz najnowszy obraz głębi otoczenia z 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.
    }
}

Aby uzyskać większą elastyczność, możesz przekonwertować nieprzetworzony obraz procesora na format RawImage. Przykład znajdziesz w przykładach ARFoundation na stronie Unity.

Interpretowanie wartości głębokości

Biorąc pod uwagę punkt A na obserwowanej geometrii w świecie rzeczywistym i punkt 2D a reprezentujący ten sam punkt na obrazie głębi, wartość podana przez interfejs Depth API w miejscu a jest równa długości obiektu CA umieszczonego na głównej osi. Nazywa się to też współrzędną z obiektu A względem źródła kamery C. Podczas pracy z interfejsem Depth API należy pamiętać, że wartości głębi to nie długość promienia CA, ale jego odwzorowanie.

Ogranicz obiekty wirtualne i wizualizuj dane o głębi

Przeczytaj posta na blogu Unity, by dowiedzieć się więcej o danych szczegółowych i ich wykorzystaniu do zasłaniania wirtualnych obrazów. Dodatkowo w przykładach ARFoundation w Unity można zobaczyć, jak zasłaniają wirtualne obrazy i wizualizują szczegółowe dane.

Stosując renderowanie dwuprzebiegowe lub renderowanie z przebiegiem w przód na obiekt, możesz zastosować przesłonięcie. Efektywność każdego podejścia zależy od złożoności sceny i innych czynników związanych z aplikacją.

Renderowanie według obiektu, przekazywanie do przodu

Renderowanie z przebiegiem w przód na poziomie obiektu decyduje o przesłonięciu każdego piksela obiektu w jego cieniowaniu. Jeśli piksele nie są widoczne, są przycinane, zwykle w ramach mieszania alfa, co powoduje symulowanie przesłonięcia na urządzeniu użytkownika.

Renderowanie dwuprzebiegowe

W przypadku renderowania dwuprzebiegowego pierwszy przebieg renderuje wszystkie wirtualne treści w buforze pośrednim. Druga opcja polega na połączeniu sceny wirtualnej z tłem w oparciu o różnicę między głębią świata rzeczywistego a wirtualną głębią sceny. To podejście nie wymaga dodatkowego cieniowania specyficznego dla obiektów i zwykle daje bardziej jednolite wyniki niż metoda przekazywania do przodu.

Wyodrębnij odległość z obrazu głębi

Aby używać interfejsu Depth API do innych celów niż zasłanianie obiektów wirtualnych lub wizualizowanie danych o głębi, wyodrębnij informacje z obrazu głębi.

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;
}

Co dalej?

  • Włącz dokładniejsze wykrywanie dzięki Raw Depth API.
  • Sprawdź ARCore Depth Lab, w którym przedstawiamy różne sposoby uzyskiwania dostępu do szczegółowych danych.