„Tiefe“ in der AR Foundation Android-App verwenden

Die Depth API hilft der Kamera eines Geräts, die Größe und Form der realen Objekte in einer Szene zu ermitteln. Dabei werden mit der Kamera Tiefenbilder oder Tiefenkarten erstellt, um Ihren Apps einen realistischen AR-Look zu verleihen. Mit den Informationen aus einem Tiefenbild können Sie virtuelle Objekte präzise vor oder hinter realen Objekten erscheinen lassen, um ein immersives und realistisches Nutzererlebnis zu ermöglichen.

Die Tiefeninformationen werden anhand der Bewegung berechnet und können mit Informationen von einem Hardware-Tiefensensor wie einem Time-of-Flight-Sensor (ToF-Sensor) kombiniert werden, sofern verfügbar. Ein Gerät benötigt keinen ToF-Sensor, um die Depth API zu unterstützen.

Vorbereitung

Machen Sie sich mit den grundlegenden AR-Konzepten und der Konfiguration einer ARCore-Sitzung vertraut, bevor Sie fortfahren.

App als Depth Required oder Depth Optional konfigurieren (nur Android)

Wenn für Ihre App die Depth API erforderlich ist, weil ein zentraler Teil der AR-Funktionen auf der Tiefenwahrnehmung basiert oder weil es keinen reibungslosen Fallback für die Teile der App gibt, die die Tiefenwahrnehmung nutzen, können Sie den Vertrieb Ihrer App im Google Play Store auf Geräte beschränken, die die Depth API unterstützen.

App Depth Required

Rufen Sie Edit > Project Settings > XR Plug-in Management > ARCore auf.

Depth ist standardmäßig auf Required festgelegt.

App Depth Optional

  1. Rufen Sie Edit > Project Settings > XR Plug-in Management > ARCore auf.

  2. Wählen Sie im Drop-down-Menü Depth die Option Optional aus, um für eine App „Tiefe optional“ festzulegen.

Tiefe aktivieren

Aus Ressourcengründen wird die Depth API in ARCore standardmäßig nicht aktiviert. Wenn Sie die Tiefeneffekte auf unterstützten Geräten nutzen möchten, müssen Sie dem Spielobjekt AR-Kamera mit den Komponenten Camera und ARCameraBackground manuell die Komponente AROcclusionManager hinzufügen. Weitere Informationen finden Sie in der Unity-Dokumentation unter Automatische Ausblendung.

Prüfen Sie in einer neuen ARCore-Sitzung, ob das Gerät eines Nutzers die Tiefenerfassung und die Depth API unterstützt. Gehen Sie dazu so vor:

// 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.
}

Tiefenbilder aufnehmen

Rufen Sie das aktuelle Umgebungstiefenbild von der AROcclusionManager ab.

// 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.
    }
}

Sie können das Roh-CPU-Image in ein RawImage konvertieren, um mehr Flexibilität zu erhalten. Ein Beispiel dazu finden Sie in den ARFoundation-Beispielen von Unity.

Tiefenwerte

Angenommen, es gibt den Punkt A in der beobachteten Geometrie der realen Welt und den 2D-Punkt a, der denselben Punkt im Tiefenbild darstellt. Der von der Depth API für a angegebene Wert entspricht der Länge von CA, projiziert auf die Hauptachse. Dies kann auch als die Z‑Koordinate von A bezogen auf den Kameraursprung C bezeichnet werden. Bei der Arbeit mit der Depth API ist es wichtig zu wissen, dass die Tiefenwerte nicht die Länge des Strahls CA selbst, sondern seine Projektion sind.

Virtuelle Objekte verdecken und Tiefendaten visualisieren

Im Blogpost von Unity finden Sie eine allgemeine Übersicht über Tiefendaten und wie sie verwendet werden können, um virtuelle Bilder zu verdecken. Außerdem zeigen die ARFoundation-Beispiele von Unity, wie virtuelle Bilder verdeckt und Tiefendaten visualisiert werden.

Sie können Occlusion mit dem zweistufigen Rendering oder dem objektspezifischen Forward-Pass-Rendering rendern. Die Effizienz der einzelnen Ansätze hängt von der Komplexität der Szene und anderen app-spezifischen Aspekten ab.

Objektspezifisches Forward-Pass-Rendering

Beim objektbasierten Forward-Pass-Rendering wird die Okklusion jedes Pixels des Objekts in seinem Material-Shader bestimmt. Wenn die Pixel nicht sichtbar sind, werden sie normalerweise durch Alpha-Blending zugeschnitten, um eine Okklusion auf dem Gerät des Nutzers zu simulieren.

Zwei-Durchlauf-Rendering

Beim zweistufigen Rendering werden beim ersten Durchlauf alle virtuellen Inhalte in einen Zwischenpuffer gerendert. Bei der zweiten Durchlauf wird die virtuelle Szene basierend auf dem Unterschied zwischen der Tiefe der realen Welt und der Tiefe der virtuellen Szene in den Hintergrund eingeblendet. Dieser Ansatz erfordert keine zusätzlichen objektspezifischen Shaderarbeiten und führt im Allgemeinen zu einheitlicheren Ergebnissen als die Forward-Pass-Methode.

Entfernung aus einem Tiefenbild extrahieren

Wenn Sie die Depth API nicht nur zum Ausblenden virtueller Objekte oder zum Visualisieren von Tiefendaten verwenden möchten, extrahieren Sie Informationen aus dem Tiefenbild.

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

Weiteres Vorgehen

  • Mit der Raw Depth API können Sie die Genauigkeit der Erfassung verbessern.
  • Im ARCore Depth Lab werden verschiedene Möglichkeiten zum Zugriff auf Tiefendaten veranschaulicht.