Explore ARKit 4
Augmented Reality 进阶 30m

探索 ARKit 4

Explore ARKit 4

2020年6月23日

在 Apple 官方观看视频

一句话判断

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