AR Foundation Android uygulamanızda Derinliği kullanma

Depth API, cihaz kamerasının bir sahnedeki gerçek nesnelerin boyutunu ve şeklini anlamasına yardımcı olur. Kamerayı kullanarak derinlikli görüntüler veya derinlik haritaları oluşturur. Böylece uygulamalarınıza artırılmış gerçeklik katmanı ekler. Sanal nesnelerin gerçek dünyadaki nesnelerin önünde veya arkasında doğru bir şekilde görünmesini sağlamak için derinlikli bir resmin sağladığı bilgileri kullanabilir, böylece sürükleyici ve gerçekçi bir kullanıcı deneyimi sağlayabilirsiniz.

Derinlik bilgileri hareketten hesaplanır ve varsa uçuş süresi (ToF) sensörü gibi bir donanım derinlik sensöründen gelen bilgilerle birleştirilebilir. Cihazların Depth API'yi desteklemek için ToF sensörü olması gerekmez.

Ön koşullar

Devam etmeden önce temel AR kavramlarını ve ARCore oturumunu nasıl yapılandıracağınızı anladığınızdan emin olun.

Uygulamanızı Depth Required veya Depth Optional olacak şekilde yapılandırın (yalnızca Android)

Uygulamanız Derinlik API'si desteği gerektiriyorsa, AR deneyiminin temel bir bölümü derinliğe dayalıysa veya uygulamanın derinliği kullanan kısımları için yedek bir çözüm olmadığından, uygulamanızın Google Play Store'da Depth API'yi destekleyen cihazlara dağıtımını kısıtlamayı seçebilirsiniz.

Uygulamanızı Depth Required yapın

Edit > Project Settings > XR Plug-in Management > ARCore adresine gidiş rotasını izle.

Depth varsayılan olarak Required değerine ayarlıdır.

Uygulamanızı Depth Optional yapın

  1. Edit > Project Settings > XR Plug-in Management > ARCore adresine gidiş rotasını izle.

  2. Bir uygulamayı derinlik isteğe bağlı olarak ayarlamak için Depth açılır menüsünden Optional öğesini seçin.

Derinliği Etkinleştir

ARCore, kaynakları kaydetmek için Derinlik API'sini varsayılan olarak etkinleştirmez. Desteklenen cihazlarda derinlikten yararlanmak için AROcclusionManager bileşenini Camera ve ARCameraBackground bileşeniyle AR Kamera oyun nesnesine manuel olarak eklemeniz gerekir. Daha fazla bilgi için Unity dokümanlarındaki Otomatik kapatma bölümüne bakın.

Yeni bir ARCore oturumunda, kullanıcının cihazının derinliği ve Depth API'yi destekleyip desteklemediğini aşağıdaki şekilde kontrol edin:

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

Derinlikli resimler edinme

AROcclusionManager'dan en yeni ortam derinliği görüntüsünü alın.

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

Daha fazla esneklik için ham CPU görüntüsünü RawImage'e dönüştürebilirsiniz. Bunun nasıl yapılacağına dair bir örneği Unity'nin ARFoundation örneklerinde bulabilirsiniz.

Derinlik değerlerini anlama

Gözlemlenen gerçek geometrideki A noktası ve derinlik resminde aynı noktayı temsil eden 2D bir nokta a verildiğinde a'de Derinlik API'si tarafından verilen değer, ana eksene yansıtılan CA uzunluğuna eşittir. Bu, C kamera kaynağına göre A öğesinin z koordinatı olarak da adlandırılabilir. Depth API ile çalışırken derinlik değerlerinin CA ışınının uzunluğu değil, onun projeksiyonu olduğunu anlamak önemlidir.

Sanal nesneleri gizleyin ve derinlik verilerini görselleştirin

Derinlikli verilere ve bu verilerin sanal görüntüleri kapatmak için nasıl kullanılabileceğine dair ileri düzey bir genel bakış için Unity'nin blog yayınına göz atın. Ayrıca, Unity'nin ARFoundation örnekleri, sanal resimlerin kapatıldığını ve derinlik verilerinin görselleştirildiğini gösterir.

İki geçişli oluşturma veya nesne başına, ileri geçiş oluşturma özelliğini kullanarak kapama işlemini oluşturabilirsiniz. Her yaklaşımın verimliliği, sahnenin karmaşıklığına ve uygulamaya özgü diğer önemli noktalara bağlıdır.

Nesne bazında, ileri geçiş oluşturma

Nesne bazında, ileriye doğru oluşturma, malzeme gölgelendiricisindeki nesnenin her bir pikselinin kapsanmasını belirler. Pikseller görünmüyorsa, genellikle alfa karıştırma kullanılarak kırpılarak kullanıcının cihazında kapama simülasyonu yapılır.

İki geçişli oluşturma

İki geçişli oluşturmada ilk geçiş, sanal içeriğin tamamını bir ara arabelleğe dönüştürür. İkinci geçişte, gerçek dünya derinliği ile sanal sahne derinliği arasındaki fark temel alınarak sanal sahneyi arka planla harmanlar. Bu yaklaşım, nesneye özgü ek bir gölgelendirici çalışması gerektirmez ve genellikle ileriye doğru geçiş yönteminden daha düzgün görünen sonuçlar üretir.

Derinlikli bir resimden mesafeyi çıkarma

Depth API'yi sanal nesneleri gizlemek veya derinlik verilerini görselleştirmek dışında amaçlar için kullanmak istiyorsanız derinlik resimdeki bilgileri çıkarın.

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

Sonraki adımlar