Utilizzare la profondità nell'app per Android AR Foundation

L'API Depth aiuta la fotocamera di un dispositivo a comprendere le dimensioni e la forma degli oggetti reali in una scena. Utilizza la fotocamera per creare immagini di profondità o mappe di profondità, aggiungendo così un livello di realismo AR alle tue app. Puoi utilizzare le informazioni fornite da un'immagine di profondità per mostrare con precisione gli oggetti virtuali davanti o dietro gli oggetti del mondo reale, consentendo esperienze immersive e realistiche per gli utenti.

Le informazioni sulla profondità vengono calcolate dal movimento e possono essere combinate con le informazioni di un sensore di profondità hardware, ad esempio un sensore di tempo di volo (ToF), se disponibile. Un dispositivo non ha bisogno di un sensore ToF per supportare l'API Depth.

Prerequisiti

Prima di procedere, assicurati di conoscere i concetti fondamentali dell'AR e come configurare una sessione ARCore.

Configurare l'app come Depth Required o Depth Optional (solo Android)

Se la tua app richiede il supporto dell'API Depth, in quanto una parte fondamentale dell'esperienza AR si basa sulla profondità o perché non è disponibile un fallback graduale per le parti dell'app che utilizzano la profondità, puoi scegliere di limitare la distribuzione della tua app nel Google Play Store ai dispositivi che supportano l'API Depth.

Crea la tua app Depth Required

Vai a Edit > Project Settings > XR Plug-in Management > ARCore.

Depth è impostato su Required per impostazione predefinita.

Crea la tua app Depth Optional

  1. Vai a Edit > Project Settings > XR Plug-in Management > ARCore.

  2. Nel menu a discesa Depth, seleziona Optional per impostare un'app su Profondità facoltativa.

Attiva profondità

Per risparmiare risorse, ARCore non attiva l'API Depth per impostazione predefinita. Per usufruire della profondità sui dispositivi supportati, devi aggiungere manualmente il componente AROcclusionManager all'oggetto di gioco Fotocamera AR con i componenti Camera e ARCameraBackground. Per ulteriori informazioni, consulta la sezione Occlusione automatica nella documentazione di Unity.

In una nuova sessione ARCore, controlla se il dispositivo di un utente supporta la profondità e l'API Depth, come segue:

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

Acquisisci immagini in 3D

Ricevi l'immagine più recente della profondità dell'ambiente da 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.
    }
}

Puoi convertire l'immagine non elaborata della CPU in un file RawImage per una maggiore flessibilità. Un esempio di come eseguire questa operazione è disponibile negli esempi ARFoundation di Unity.

Informazioni sui valori di profondità

Dato il punto A sulla geometria del mondo reale osservata e un punto 2D a rappresentante lo stesso punto nell'immagine di profondità, il valore fornito dall'API Depth in a è uguale alla lunghezza di CA proiettata sull'asse principale. Può anche essere indicata come la coordinata z di A rispetto all'origine della camera C. Quando si utilizza l'API Depth, è importante capire che i valori di profondità non sono la lunghezza del raggio CA stesso, ma la sua proiezione.

Occludere oggetti virtuali e visualizzare i dati di profondità

Dai un'occhiata al post del blog di Unity per una panoramica generale dei dati di profondità e su come possono essere utilizzati per occultare le immagini virtuali. Inoltre, i samples ARFoundation di Unity mostrano l'occlusione di immagini virtuali e la visualizzazione dei dati di profondità.

Puoi eseguire il rendering dell'occlusione utilizzando il rendering a due passaggi o il rendering per oggetto con passaggio in avanti. L'efficienza di ciascun approccio dipende dalla complessità della scena e da altre considerazioni specifiche dell'app.

Rendering per oggetto con passaggio in avanti

Il rendering per oggetto con passaggio in avanti determina l'occlusione di ogni pixel dell'oggetto nel relativo shader del materiale. Se i pixel non sono visibili, vengono tagliati, in genere tramite la miscelazione alfa, simulando così l'occlusione sul dispositivo dell'utente.

Rendering in due passaggi

Con il rendering in due passaggi, il primo passaggio esegue il rendering di tutti i contenuti virtuali in un buffer intermedio. Il secondo passaggio fonde la scena virtuale sullo sfondo in base alla differenza tra la profondità del mondo reale e la profondità della scena virtuale. Questo approccio non richiede alcun lavoro aggiuntivo sugli shader specifici per oggetto e in genere produce risultati dall'aspetto più uniforme rispetto al metodo di passaggio in avanti.

Estrarre la distanza da un'immagine in 3D

Per utilizzare l'API Depth per scopi diversi dall'occultamento di oggetti virtuali o dalla visualizzazione dei dati di profondità, estrai le informazioni dall'immagine di profondità.

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

Passaggi successivi

  • Attiva un rilevamento più preciso con l'API Raw Depth.
  • Dai un'occhiata ad ARCore Depth Lab, che mostra diversi modi per accedere ai dati di profondità.