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 en una escena. Usa la cámara para crear imágenes de profundidad 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 que los objetos virtuales aparezcan de manera precisa delante o detrás de objetos del mundo real, lo que proporciona experiencias del usuario envolventes 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 la 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 depende de la profundidad o porque no hay un resguardo elegante para las partes de la app que usan profundidad, puedes restringir la distribución de tu app en Google Play Store a dispositivos que admitan la API de Depth.

Crea tu app Depth Required

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

Depth se establece en Required de forma predeterminada.

Crea tu app Depth Optional

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

  2. En el menú desplegable Depth, selecciona Optional para establecer una app como opcional para la profundidad.

Habilita la profundidad

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

En una nueva sesión de ARCore, verifica si el dispositivo de un usuario admite la 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 de profundidad del entorno más reciente 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 sin procesar de la CPU en una RawImage para obtener mayor flexibilidad. Puedes encontrar un ejemplo de cómo hacerlo en los ejemplos de ARFoundation de Unity.

Comprende los valores de profundidad

Dado el punto A en la geometría observada del mundo real y un punto 2D a que representa el mismo punto en la imagen de profundidad, el valor que proporciona la API de Depth en a es igual a la longitud de CA proyectada en el eje principal. Esto también se puede denominar la coordenada z de A en relación con el origen de la cámara C. Cuando se trabaja con la API de Depth, es importante comprender que los valores de profundidad no son la longitud del rayo CA en sí, sino su proyección.

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, los ejemplos de ARFoundation de Unity demuestran cómo ocluir imágenes virtuales y visualizar datos de profundidad.

Puedes renderizar la oclusión con renderización de dos pases o renderización de paso directo por objeto. La eficiencia de cada enfoque depende de la complejidad de la escena y de otras consideraciones específicas de la app.

Renderización de paso directo por objeto

La renderización de paso directo por objeto determina la oclusión de cada píxel del objeto en su sombreador de materiales. Si los píxeles no son visibles, se recortan, por lo general, mediante la combinación alfa, lo que simula la oclusión en el dispositivo del usuario.

Renderización de dos pases

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

Cómo extraer la distancia de una imagen de profundidad

Para usar la API de Depth con fines distintos de ocluir objetos virtuales o 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?

  • Habilita una detección más precisa con la API de Raw Depth.
  • Consulta el ARCore Depth Lab, que muestra diferentes formas de acceder a los datos de profundidad.