Augmented Reality 进阶 30m
探索 ARKit 4
Explore ARKit 4
2020年6月23日
一句话判断
ARKit 4 带来了位置锚定(Location Anchors)和深度 API——前者让 AR 内容可以固定在真实世界的地理坐标上,后者让你可以精确理解场景的 3D 结构。
这场 Session 讲了什么
这场 Session 全面介绍了 ARKit 4 的核心更新。ARKit 自 2017 年发布以来每年都有重大更新,2020 年的第四版带来了两个标志性功能:ARLocationAnchor(位置锚定)和 Depth API(深度数据访问)。
位置锚定允许开发者将 AR 内容放置在真实的地理坐标上。比如你可以在某个地标建筑旁放置一个虚拟的信息牌,任何人拿着 iPhone 走到那个位置都能看到。这个功能利用了 Apple Maps 的高精度地理数据,在支持的城市中可以精确到厘米级别。配合 ARGeoTrackingConfiguration,ARKit 可以将 GPS 定位、视觉定位和 IMU 数据融合,实现户外场景下的稳定追踪。
Depth API 让开发者可以访问 LiDAR 扫描仪(iPad Pro 2020 首次搭载)或双摄系统生成的场景深度数据。这意味着你可以精确知道场景中每个像素到相机的距离,用于实现更真实的遮挡效果(虚拟物体被真实物体遮挡)、物理交互(虚拟球碰到真实墙壁会弹回来),以及场景理解(识别地面、墙壁、家具等)。
Session 还介绍了 Scene Geometry API,它可以将真实场景重建为 3D 网格模型,供物理引擎和碰撞检测使用。
值得深挖的点
- 位置锚定的城市覆盖范围:ARLocationAnchor 依赖 Apple Maps 预先采集的街道级 3D 数据,因此只在特定城市可用(主要是美国主要城市)。在其他地区,位置锚定的精度会显著下降。如果你的 AR 应用面向全球市场,需要做好不支持地区的降级方案。
- LiDAR 对 AR 体验的革命性影响:搭载 LiDAR 的设备在暗光环境下的追踪稳定性有质的飞跃,场景重建的精度也远超基于视觉的方法。这意味着你的 AR 应用在 LiDAR 设备和非 LiDAR 设备上会有体验差异,需要在设计层面就考虑到。
代码片段
// 使用 ARLocationAnchor 放置地理位置锚定的 AR 内容
import ARKit
class GeoAnchoredViewController: UIViewController {
var arView: ARView!
func addLocationAnchor() {
// 检查地理位置追踪是否可用
guard ARGeoTrackingConfiguration.isSupported else {
print("此设备/地区不支持地理位置追踪")
return
}
let config = ARGeoTrackingConfiguration()
arView.session.run(config)
// 在特定经纬度放置 AR 内容
let coordinate = CLLocationCoordinate2D(
latitude: 37.7749, longitude: -122.4194
)
let locationAnchor = ARLocationAnchor(
coordinate: coordinate,
altitude: 10
)
// 添加虚拟内容
let model = ModelEntity(mesh: .generateBox(size: 0.5))
model.model?.materials = [SimpleMaterial(color: .blue, isMetallic: true)]
locationAnchor.addChild(model)
arView.scene.addAnchor(locationAnchor)
}
}
// 使用 Depth API 获取场景深度数据
func session(_ session: ARSession, didUpdate frame: ARFrame) {
guard let depthData = frame.sceneDepth else { return }
let depthMap = depthData.depthMap
let confidenceMap = depthData.confidenceMap
// depthMap 是一个 CVPixelBuffer,每个像素值代表到相机的距离(米)
CVPixelBufferLockBaseAddress(depthMap, .readOnly)
let depthPointer = CVPixelBufferGetBaseAddress(depthMap)
let depthFloats = depthPointer?.bindMemory(
to: Float32.self,
capacity: CVPixelBufferGetWidth(depthMap) * CVPixelBufferGetHeight(depthMap)
)
// 获取中心点的深度值
let centerX = CVPixelBufferGetWidth(depthMap) / 2
let centerY = CVPixelBufferGetHeight(depthMap) / 2
let distance = depthFloats?[centerY * CVPixelBufferGetWidth(depthMap) + centerX] ?? 0
print("前方 \(distance) 米处有物体")
CVPixelBufferUnlockBaseAddress(depthMap, .readOnly)
}
// 使用 Scene Geometry 进行场景重建
func setupSceneReconstruction() {
let config = ARWorldTrackingConfiguration()
config.sceneReconstruction = .mesh // 启用网格重建
arView.session.run(config)
}
// 获取重建的网格用于物理碰撞
func processMeshAnchors() {
guard let meshAnchors = arView.session.currentFrame?.anchors
.compactMap({ $0 as? ARMeshAnchor }) else { return }
for meshAnchor in meshAnchors {
let geometry = meshAnchor.geometry
// 将网格数据转换为可用于物理碰撞的形状
let shape = ShapeResource.generateStaticMesh(
from: geometry
)
}
}
最佳实践
- 使用地理位置追踪前务必检查
ARGeoTrackingConfiguration.isSupported,做好不支持设备/地区的降级处理 - 深度数据的使用要考虑性能开销,不需要每帧都处理完整的深度图
- 利用 Scene Geometry 生成的碰撞网格让虚拟物体与真实环境进行物理交互
- AR 场景中的光照使用 ARKit 的环境光估计(AREnvironmentProbeAnchor)来匹配真实光照
- 在 LiDAR 设备上利用快速平面检测提升 AR 体验的启动速度
还有什么值得关注
- LiDAR 后来在 iPhone 12 Pro 系列上也搭载了,ARKit 4 的深度 API 适用范围比 2020 年初预期的更广
- “What’s new in RealityKit” 介绍了 RealityKit 如何适配 ARKit 4 的新功能
- 如果你在做 AR 电商,搭配 “Shop online with AR Quick Look” 一起看
WWDC 2020