Utiliser la fonctionnalité Depth dans votre application Android AR Foundation

L'API Depth aide la caméra d'un appareil à comprendre la taille et la forme des objets réels d'une scène. Elle utilise l'appareil photo pour créer des images de profondeur, ou cartes de profondeur, et ajoute ainsi un niveau de réalisme de la RA à vos applications. Vous pouvez utiliser les informations fournies par une représentation de profondeur pour faire apparaître avec précision des objets virtuels devant ou derrière des objets du monde réel, offrant ainsi des expériences utilisateur immersives et réalistes.

Les informations de profondeur sont calculées à partir des mouvements et peuvent être combinées à celles d'un capteur matériel de profondeur, tel qu'un capteur de durée de vol, si disponible. Un appareil n'a pas besoin d'un capteur ToF pour être compatible avec l'API Depth.

Prérequis

Avant de continuer, assurez-vous de bien comprendre les concepts fondamentaux de la RA et de savoir configurer une session ARCore.

Configurer votre application en tant que Depth Required ou Depth Optional (Android uniquement)

Si votre application nécessite la prise en charge de l'API Depth, soit parce qu'une partie essentielle de l'expérience de RA repose sur la profondeur, soit parce qu'il n'existe pas de solution de remplacement élégante pour les parties de l'application qui utilisent la profondeur, vous pouvez choisir de limiter la distribution de votre application sur le Google Play Store aux appareils compatibles avec l'API Depth.

Rendre votre application Depth Required

Accédez à Edit > Project Settings > XR Plug-in Management > ARCore.

Depth est défini par défaut sur Required.

Rendre votre application Depth Optional

  1. Accédez à Edit > Project Settings > XR Plug-in Management > ARCore.

  2. Dans le menu déroulant Depth, sélectionnez Optional pour définir une application sur "Profondeur facultative".

Activer la profondeur

Pour économiser des ressources, ARCore n'active pas l'API Depth par défaut. Pour exploiter la profondeur sur les appareils compatibles, vous devez ajouter manuellement le composant AROcclusionManager à l'objet de jeu Caméra RA avec les composants Camera et ARCameraBackground. Pour en savoir plus, consultez la section Occlusion automatique dans la documentation Unity.

Dans une nouvelle session ARCore, vérifiez si l'appareil de l'utilisateur est compatible avec la profondeur et l'API Depth, comme suit:

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

Acquérir des images de profondeur

Obtenez la dernière image de profondeur de l'environnement à partir de 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.
    }
}

Vous pouvez convertir l'image du processeur brut en RawImage pour plus de flexibilité. Vous trouverez un exemple de procédure dans les exemples ARFoundation d'Unity.

Comprendre les valeurs de profondeur

Étant donné le point A sur la géométrie du monde réel observée et un point 2D a représentant le même point dans l'image de profondeur, la valeur donnée par l'API Depth à a est égale à la longueur de CA projetée sur l'axe principal. On peut également parler de la coordonnée z de A par rapport à l'origine de la caméra C. Lorsque vous travaillez avec l'API Depth, il est important de comprendre que les valeurs de profondeur ne correspondent pas à la longueur du rayon CA lui-même, mais à sa projection.

Masquer des objets virtuels et visualiser des données de profondeur

Consultez l'article de blog d'Unity pour obtenir une présentation générale des données de profondeur et de la façon dont elles peuvent être utilisées pour masquer des images virtuelles. De plus, les exemples ARFoundation d'Unity montrent l'occlusion d'images virtuelles et la visualisation des données de profondeur.

Vous pouvez effectuer le rendu de l'occlusion à l'aide d'un rendu en deux passes ou d'un rendu par objet, en mode de rendu direct. L'efficacité de chaque approche dépend de la complexité de la scène et d'autres considérations propres à l'application.

Rendu par objet, avec pass avant

Le rendu par objet en pass avant détermine l'occlusion de chaque pixel de l'objet dans son nuanceur de matière. Si les pixels ne sont pas visibles, ils sont rognés, généralement via un mélange alpha, ce qui simule l'occlusion sur l'appareil de l'utilisateur.

Rendu en deux passes

Avec le rendu en deux passes, la première passe effectue le rendu de l'intégralité du contenu virtuel dans un tampon intermédiaire. La deuxième passe mélange la scène virtuelle à l'arrière-plan en fonction de la différence entre la profondeur réelle et la profondeur de la scène virtuelle. Cette approche ne nécessite aucun travail supplémentaire du nuanceur spécifique aux objets et produit généralement des résultats d'apparence plus uniformes que la méthode de transmission avant.

Extraire la distance à partir d'une image de profondeur

Pour utiliser l'API Depth à d'autres fins que l'occlusion d'objets virtuels ou la visualisation de données de profondeur, extrayez des informations de l'image de profondeur.

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

Étapes suivantes