„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. Geräte benötigen zur Unterstützung der Depth API keinen ToF-Sensor.

Voraussetzungen

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

Konfiguriere deine App als Depth Required oder Depth Optional (nur Android)

Wenn für deine App Depth API-Unterstützung erforderlich ist, weil ein zentraler Bestandteil des AR-Erlebnisses auf Tiefe basiert oder es kein Graceful Fallback für Teile der App gibt, die Tiefe verwenden, kannst du den Vertrieb der App im Google Play Store auf Geräte beschränken, die die Depth API unterstützen.

App zu Depth Required machen

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

Depth ist standardmäßig auf Required festgelegt.

App zu Depth Optional machen

  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 Okklusion.

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

Bei Punkt A in der beobachteten realen Geometrie und einem 2D-Punkt a, der denselben Punkt im Tiefenbild darstellt, entspricht der von der Depth API bei a angegebene Wert der Länge von CA, die auf die Hauptachse projiziert wird. 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 ausblenden und Tiefendaten visualisieren

Im Blogpost von Unity finden Sie einen allgemeinen Überblick über detaillierte Daten und wie sie zum Verdecken virtueller Bilder verwendet werden können. 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 weiteren anwendungsspezifischen Aspekten ab.

Vorwärtsdurchlauf-Rendering pro Objekt

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 abgeschnitten, in der Regel durch Alpha-Überblendung, um eine Verdeckung auf dem Gerät des Nutzers zu simulieren.

Zwei-Pass-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 Shader-Arbeiten 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

  • Ermöglichen Sie eine genauere Erkennung mit der Raw Depth API.
  • Im ARCore Depth Lab werden verschiedene Möglichkeiten für den Zugriff auf detaillierte Daten vorgestellt.