深度 API 可協助裝置的相機瞭解場景中實際物體的大小和形狀。這項功能會使用相機建立深度圖片或深度地圖,進而在應用程式中加入 AR 寫實程度層。您可以運用深度圖片提供的資訊,精準地將虛擬物件顯示在真實世界中或實際物件後方,為使用者帶來身歷其境的沉浸式體驗。
深度資訊是根據動作計算而得,可能會與硬體深度感應器 (例如飛行時間 (ToF) 感應器) 的資訊 (如果有的話) 合併計算。裝置不需要 ToF 感應器來支援 Depth API。
必要條件
請務必先瞭解基本 AR 概念,以及如何設定 ARCore 工作階段,然後再繼續操作。
將應用程式設為 Depth Required 或 Depth Optional (僅限 Android)
如果應用程式需要 Depth API 支援 (AR 體驗的核心部分需要仰賴深度),或者因為使用深度的應用程式部分沒有流暢的備用方案,您可以選擇將應用程式在 Google Play 商店中的發行範圍限制為支援 Depth API 的裝置。
讓應用程式Depth Required
前往 Edit > Project Settings > XR Plug-in Management > ARCore。
Depth 預設為 Required。
讓應用程式Depth Optional
前往 Edit > Project Settings > XR Plug-in Management > ARCore。
在 Depth 下拉式選單中選取 Optional,將應用程式設為選用深度。
啟用深度
為了節省資源,ARCore 預設不會啟用 Depth API。如要在支援的裝置上利用深度,您必須使用 Camera
和 ARCameraBackground
元件,將 AROcclusionManager
元件手動新增至 AR 相機的遊戲物件。詳情請參閱 Unity 說明文件中的自動遮蔽。
請在新的 ARCore 工作階段中,檢查使用者的裝置是否支援深度和深度 API,如下所示:
// 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.
}
取得深度圖片
從 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.
}
}
你可以將原始 CPU 映像檔轉換為 RawImage
,以便享有更高的彈性。如需相關範例,請參閱 Unity 的 ARFoundation 範例。
瞭解深度值
假設在觀察到的實際幾何圖形上,點為 A
,且 2D 點 a
代表深度圖片中的相同點,因此 a
的深度 API 提供的值等於投影至主體軸的 CA
長度。也稱為相對於相機來源 C
的 A
Z 座標。使用 Depth API 時,請務必瞭解深度值不是光線 CA
本身的長度,而是其「投影」。
遮蔽虛擬物件,以視覺化方式呈現深度資料
請參閱 Unity 的網誌文章,瞭解深度資料的概要總覽,以及如何使用資料遮蔽虛擬圖片。此外,Unity 的 ARFoundation 範例會示範遮蔽虛擬圖像,並以視覺化方式呈現深度資料。
您可以使用兩道轉譯或個別物件的前向轉譯來呈現遮蔽。每種方法的效率取決於場景的複雜程度及其他應用程式具體考量。
個別物件、正向傳遞轉譯
個別物件的正向傳遞轉譯會決定其 Material 著色器中每個像素的遮蔽。如果無法看見像素,就會遭到裁切 (通常是透過 Alpha 混合) 裁剪,在使用者裝置上模擬遮蔽。
兩段式轉譯
採用兩段轉譯機制時,第一個傳遞會將所有虛擬內容算繪到中介緩衝區中。第二通道會根據實際景深與虛擬場景深度之間的差異,將虛擬場景融入背景。這個方法不需要額外的物件專用著色器運作,而且通常能產生比正向傳遞方法更一致的結果。
擷取深度圖片的距離
如要將深度 API 用於遮蔽虛擬物件或以視覺化方式呈現深度資料的用途,請從深度圖片中擷取資訊。
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;
}
後續步驟
- 透過 Raw Depth API 啟用更準確的感應功能。
- 請瀏覽 ARCore 深度研究室,瞭解存取深度資料的幾種不同方式。