Khai thác thông tin chuyên sâu trong ứng dụng AR Foundation trên Android

Depth API (API Chiều sâu) giúp camera trên thiết bị hiểu được kích thước và hình dạng của các đối tượng thực trong một cảnh. Tính năng này sử dụng camera để tạo hình ảnh chiều sâu hay bản đồ độ sâu, do đó thêm một lớp hiện thực AR vào ứng dụng của bạn. Bạn có thể sử dụng thông tin do hình ảnh chiều sâu cung cấp để làm cho các đối tượng ảo xuất hiện chính xác ở phía trước hoặc phía sau các đối tượng trong thế giới thực, nhờ đó mang lại trải nghiệm sống động và chân thực cho người dùng.

Thông tin về độ sâu được tính toán từ chuyển động và có thể được kết hợp với thông tin từ cảm biến độ sâu phần cứng, chẳng hạn như cảm biến thời gian bay (ToF), nếu có. Thiết bị không cần có cảm biến ToF để hỗ trợ depth API.

Điều kiện tiên quyết

Đảm bảo rằng bạn hiểu rõ các khái niệm cơ bản về AR và cách định cấu hình phiên ARCore trước khi tiếp tục.

Định cấu hình ứng dụng của bạn thành Depth Required hoặc Depth Optional (chỉ dành cho Android)

Nếu ứng dụng của bạn cần hỗ trợ API Độ sâu, vì một phần cốt lõi của trải nghiệm AR phụ thuộc vào chiều sâu, hoặc vì không có giải pháp dự phòng phù hợp nào cho các phần của ứng dụng sử dụng chiều sâu, bạn có thể chọn hạn chế phân phối ứng dụng của bạn trong Cửa hàng Google Play đến những thiết bị hỗ trợ depth API.

Thiết lập ứng dụng Depth Required

Chuyển đến Edit > Project Settings > XR Plug-in Management > ARCore.

Theo mặc định, Depth được đặt thành Required.

Thiết lập ứng dụng Depth Optional

  1. Chuyển đến Edit > Project Settings > XR Plug-in Management > ARCore.

  2. Trong trình đơn thả xuống Depth, hãy chọn Optional để đặt một ứng dụng ở chế độ Độ sâu.

Bật tính năng Chiều sâu

Để tiết kiệm tài nguyên, theo mặc định, ARCore không bật depth API. Cần thực hiện trên các thiết bị được hỗ trợ, bạn phải tự thêm AROcclusionManager thành phần cho đối tượng trò chơi AR Camera với Camera và Thành phần ARCameraBackground. Xem Tự động che khuất trong tài liệu Unity để biết thêm thông tin.

Trong phiên ARCore mới, hãy kiểm tra xem thiết bị của người dùng hỗ trợ depth và API depth như sau:

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

Thu thập hình ảnh có chiều sâu

Tải hình ảnh chiều sâu của môi trường mới nhất từ 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.
    }
}

Bạn có thể chuyển đổi hình ảnh CPU thô thành RawImage để linh hoạt hơn. Một Bạn có thể xem ví dụ về cách thực hiện việc này trong các mẫu ARFoundation của Unity.

Tìm hiểu các giá trị độ sâu

Cho điểm A trên hình học thực tế đã quan sát và điểm 2D a đại diện cho cùng một điểm trong hình ảnh chiều sâu, giá trị được cho bởi Độ sâu API tại a bằng độ dài của CA được chiếu lên trục chính. Đây cũng có thể được gọi là toạ độ z của A so với camera máy chủ gốc C. Khi làm việc với depth API, bạn cần hiểu rằng giá trị độ sâu không phải là độ dài của tia CA mà là hình chiếu nội dung.

Che khuất các đối tượng ảo và trực quan hoá dữ liệu chiều sâu

Hãy xem bài đăng trên blog của Unity để có thông tin tổng quan cấp cao về dữ liệu chiều sâu và cách dữ liệu đó có thể được dùng để che khuất hình ảnh ảo. Ngoài ra, các phiên bản Mẫu ARFoundation minh hoạ việc che khuất hình ảnh ảo và trực quan hoá dữ liệu chiều sâu.

Bạn có thể kết xuất hiệu ứng che khuất bằng cách sử dụng phương pháp kết xuất hai chiều hoặc kết xuất theo từng đối tượng và kết xuất chuyển tiếp. Hiệu quả của mỗi phương pháp phụ thuộc vào mức độ phức tạp của cảnh và các yếu tố khác cần cân nhắc dành riêng cho ứng dụng.

Kết xuất chuyển tiếp trên mỗi đối tượng

Tính năng kết xuất theo từng đối tượng xác định độ che khuất từng pixel của đối tượng trong chương trình đổ bóng chất liệu. Nếu các pixel không hiển thị, thì chúng sẽ bị cắt bớt, thường là bằng cách phối màu alpha, nhờ đó mô phỏng việc che khuất trên thiết bị của người dùng.

Kết xuất hai lượt

Với tính năng kết xuất hai lượt, lượt truyền đầu tiên sẽ kết xuất tất cả nội dung ảo vào một vùng đệm trung gian. Lượt thứ hai kết hợp cảnh ảo với nền dựa trên sự chênh lệch giữa độ sâu của thế giới thực với độ sâu của cảnh ảo. Phương pháp này không yêu cầu thêm hoạt động đổ bóng dành riêng cho đối tượng nào và thường tạo ra kết quả đồng nhất hơn phương thức chuyển tiến.

Trích xuất khoảng cách từ hình ảnh chiều sâu

Để sử dụng depth API cho các mục đích khác ngoài mục đích che khuất đối tượng ảo hoặc trực quan hoá dữ liệu về độ sâu, hãy trích xuất thông tin từ hình ảnh chiều sâu.

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

Bước tiếp theo