Depth 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 会话中,检查用户的设备是否支持深度和 Depth 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
,Depth API 在 a
处给出的值等于投影到主轴上的 CA
的长度。这也可称为 A
相对于相机原点 C
的 z 坐标。使用 Depth API 时,请务必注意,深度值不是光线 CA
本身的长度,而是光线的投影。
遮挡虚拟对象并直观呈现深度数据
请参阅 Unity 的博文,简要了解深度数据以及如何使用它来遮盖虚拟图像。此外,Unity 的 ARFoundation 示例展示了如何遮挡虚拟图像以及将深度数据可视化。
您可以使用双通道渲染或每个对象的前向渲染来渲染遮挡。每种方法的效率取决于场景的复杂性和其他特定于应用的注意事项。
每个对象的前向传递渲染
每个对象的前向渲染决定了对象在其 Material 着色器中的遮挡效果。如果像素不可见,系统会对其进行裁剪(通常通过 alpha 混合),从而在用户设备上模拟遮挡。
双通道渲染
采用双通道渲染时,第一通道会将所有虚拟内容渲染到中间缓冲区中。第二通道根据现实世界深度与虚拟场景深度之间的差异,将虚拟场景与背景混合。与前向方法相比,这种方法不需要额外的对象特定着色器工作,并且通常会产生更加一致的结果。
从深度图像中提取距离
如需将 Depth 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 深度实验室,其中演示了获取深度数据的不同方法。