Usa Depth en tu app de AR Foundation para Android

La API de Depth ayuda a la cámara de un dispositivo a comprender el tamaño y la forma de los objetos reales de una escena. Usa la cámara para crear imágenes o mapas de profundidad, lo que agrega una capa de realismo de RA a tus apps. Puedes usar la información que proporciona una imagen de profundidad para hacer que los objetos virtuales aparezcan con precisión delante o detrás de objetos del mundo real, lo que permite experiencias del usuario inmersivas y realistas.

La información de profundidad se calcula a partir del movimiento y se puede combinar con la información de un sensor de profundidad de hardware, como un sensor de tiempo de vuelo (ToF), si está disponible. Un dispositivo no necesita un sensor ToF para admitir la API de Depth.

Requisitos previos

Asegúrate de comprender los conceptos fundamentales de RA y cómo configurar una sesión de ARCore antes de continuar.

Configura tu app para que sea Depth Required o Depth Optional (solo para Android)

Si tu app requiere compatibilidad con la API de Depth, ya sea porque una parte fundamental de la experiencia de RA se basa en la profundidad no hay resguardo correcto para las partes de la app que usan profundidad, puedes restringir la distribución de tu app en Google Play Store para dispositivos compatibles con la API de Depth.

Configura tu app como Depth Required

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

Depth se establece en Required de forma predeterminada.

Configura tu app como Depth Optional

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

  2. En el menú desplegable Depth, selecciona Optional. para configurar la Profundidad de una app como opcional.

Habilitar profundidad

Para ahorrar recursos, ARCore no habilita la API de Depth de forma predeterminada. Para tomar de profundidad en dispositivos compatibles, debes agregar manualmente el AROcclusionManager al objeto de juego de Cámara de RA con las funciones Camera y ARCameraBackground. Consulta Oclusión automática en la documentación de Unity para obtener más información.

En una sesión nueva de ARCore, verifica si se muestra El dispositivo del usuario admite profundidad y la API de Depth, de la siguiente manera:

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

Cómo adquirir imágenes de profundidad

Obtén la imagen más reciente sobre la profundidad del entorno del 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.
    }
}

Puedes convertir la imagen de CPU sin procesar en un RawImage. para una mayor flexibilidad. Los Puedes encontrar un ejemplo de cómo hacerlo en las muestras de ARFoundation de Unity.

Cómo interpretar los valores de profundidad

Dado el punto A en la geometría del mundo real observada y un punto 2D a que representan el mismo punto en la imagen de profundidad, el valor que otorga la profundidad La API en a es igual a la longitud de CA proyectada en el eje principal. También se puede denominar la coordenada z de A en relación con la cámara. origen C. Cuando trabajes con la API de Depth, es importante que comprendas lo siguiente: Los valores de profundidad no son la longitud del rayo CA, sino la proyección de sus aspectos más emocionantes.

Oculta objetos virtuales y visualiza datos de profundidad

Consulta la entrada de blog de Unity para obtener una descripción general de alto nivel de los datos de profundidad y cómo se pueden usar para ocluir imágenes virtuales. Además, la base de datos Muestras de ARFoundation demostrar la oclusión de imágenes virtuales y la visualización de datos de profundidad.

Puedes renderizar la oclusión con renderización de dos pasos o por objeto, renderizado de pase hacia delante. La eficiencia de cada enfoque depende de la complejidad de la escena y otras consideraciones específicas de la app.

Renderización de pase hacia delante por objeto

La renderización de pase hacia delante por objeto determina la oclusión de cada píxel del objeto en el sombreador de material. Si los píxeles no son visibles, se recortan, generalmente, mediante una combinación alfa, con lo que se simula la oclusión en el dispositivo del usuario.

Renderización de dos pasos

Con la renderización de dos pasos, el primer pase renderiza todo el contenido virtual en un búfer intermedio. El segundo pase combina la escena virtual con el fondo en función de la diferencia entre la profundidad del mundo real y la profundidad de la escena virtual. Este enfoque no requiere trabajo adicional de sombreador específico del objeto y, por lo general, produce resultados más uniformes que el método de pase hacia delante.

Cómo extraer la distancia de una imagen de profundidad

Si quieres usar la API de Depth con otros fines que no sean para ocultar objetos virtuales ni visualizar datos de profundidad, extrae información de la imagen de profundidad.

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

¿Qué sigue?