WWDC Quick Look 💓 By SwiftGGTeam
Explore ARKit 4

Explore ARKit 4

观看原视频

Highlight

ARKit 4 增加了地理位置锚点、LiDAR 场景深度、改进的光线投射和更广设备覆盖的面部追踪,让 AR 内容能绑定真实坐标、读取米级深度并更快完成物体放置。

核心内容

以前做户外 AR,最大的麻烦是坐标。GPS 能告诉 App 大概在哪里,却不能把一个虚拟标牌稳定放在街角某栋楼前。开发者还要处理本地 AR 坐标和地理坐标之间的转换,用户走几步,虚拟内容就可能漂移。

ARKit 4 把这个问题收进框架。开发者给出经纬度和可选海拔,ARGeoTrackingConfiguration 会结合 Apple Maps 的高精度地图数据、摄像头图像和设备运动数据,完成视觉定位。App 获得的是一个全局感知的 AR pose,虚拟内容可以固定在真实世界的位置。

室内 AR 的痛点也很直接。以前要等平面检测稳定,白墙这类缺少特征的表面会让放置过程变慢。ARKit 3.5 先用 LiDAR 带来场景几何,iOS 14 又开放 Depth API。开发者可以拿到每帧的深度图,也可以让 raycasting 自动利用深度或场景网格,把物体更快放到真实表面上。

这场 Session 的主线很清楚:ARKit 4 把 AR 从“房间里的局部坐标”推进到“真实世界里的位置、深度和表面”。位置锚点解决户外共享位置,Depth API 解决真实场景距离,raycasting 解决放置速度,Face Tracking 则把面部 AR 扩展到更多 A12 或更新芯片设备。

详细内容

地理位置锚点:先确认设备和地点

06:58)位置锚点从 ARGeoTrackingConfiguration 开始。Session 明确要求先检查两件事:设备是否支持 geo tracking,当前位置是否有足够的地图数据用于视觉定位。

// Check device support for geo-tracking
guard ARGeoTrackingConfiguration.isSupported else {
    // Geo-tracking not supported on this device
    return
}

// Check current location is supported for geo-tracking
ARGeoTrackingConfiguration.checkAvailability { (available, error) in
    guard available else {
        // Geo-tracking not supported at current location
        return
    }
    // Run ARSession
    let arView = ARView()
    arView.session.run(ARGeoTrackingConfiguration())
}

关键点:

  • ARGeoTrackingConfiguration.isSupported 先挡住不支持的硬件,Session 提到位置锚点需要 A12 Bionic 或更新芯片以及 GPS。
  • checkAvailability 检查当前地点是否有用于定位的 Apple Maps 数据。
  • 通过检查后,ARView 的 session 才运行 ARGeoTrackingConfiguration()
  • ARKit 会在 session 启动时请求相机和位置权限,失败时要把错误解释给用户。

用 ARGeoAnchor 绑定真实经纬度

08:38)Session 用旧金山 Ferry Building 做示例。开发者创建 CLLocationCoordinate2D,再创建 ARGeoAnchor,最后把 RealityKit 的实体挂到这个锚点上。

// Create coordinates
let coordinate = CLLocationCoordinate2D(latitude: 37.795313, longitude: -122.393792)

// Create Location Anchor
let geoAnchor = ARGeoAnchor(name: "Ferry Building", coordinate: coordinate)

// Add Location Anchor to session
arView.session.add(anchor: geoAnchor)

// Create a RealityKit anchor entity
let geoAnchorEntity = AnchorEntity(anchor: geoAnchor)

// Anchor content under the RealityKit anchor
geoAnchorEntity.addChild(generateSignEntity())

// Add the RealityKit anchor to the scene
arView.scene.addAnchor(geoAnchorEntity)

关键点:

  • CLLocationCoordinate2D 使用至少 6 位小数精度,Session 用它保证内容能准确放到地点上。
  • ARGeoAnchor(name:coordinate:) 只传经纬度时,ARKit 会用地图数据推断地面海拔。
  • arView.session.add(anchor:) 把地理锚点交给 ARKit 管理。
  • AnchorEntity(anchor:) 让 RealityKit 内容跟随这个 ARKit 锚点。
  • generateSignEntity() 代表要显示的虚拟标牌,实际 App 可以替换为模型、说明牌或导航提示。

锚点方向固定,内容变换交给渲染层

10:32ARGeoAnchor 的坐标轴固定到方位:X 轴指向东,Z 轴指向南,Y 轴向上。锚点本身不可变,旋转和抬高内容要在 RealityKit 实体上完成。

// Create a new entity for our virtual content
let signEntity = generateSignEntity();

// Add the virtual content entity to the Geo Anchor entity
geoAnchorEntity.addChild(signEntity)

// Rotate text to face the city
let orientation = simd_quatf.init(angle: -Float.pi / 3.5, axis: SIMD3<Float>(0, 1, 0))
signEntity.setOrientation(orientation, relativeTo: geoAnchorEntity)

// Elevate text to 35 meters above ground level
let position = SIMD3<Float>(0, 35, 0)
signEntity.setPosition(position, relativeTo: geoAnchorEntity)

关键点:

  • generateSignEntity() 创建要显示的内容实体。
  • geoAnchorEntity.addChild(signEntity) 把内容放到地理锚点的局部坐标系里。
  • simd_quatf 绕 Y 轴旋转,让文字面向城市方向。
  • setOrientation(_:relativeTo:) 以地理锚点为参照设置朝向。
  • SIMD3<Float>(0, 35, 0) 把标牌抬高 35 米,适合远距离识别。

用户点击也能生成地理坐标

14:08)地理坐标不一定来自数据库。用户点击屏幕后,App 可以从 ARKit 世界坐标反查地理位置,再保存为新的位置锚点。

let session = ARSession()
let worldPosition = raycastLocationFromUserTap()
session.getGeoLocation(forPoint: worldPosition) { (location, altitude, error) in
    if let error = error {
        ...
    }
    let geoAnchor = ARGeoAnchor(coordinate: location, altitude: altitude)
}

关键点:

  • raycastLocationFromUserTap() 表示从用户点击位置得到 AR 世界坐标,Session 提到它可以来自 raycast 或平面上的点。
  • getGeoLocation(forPoint:) 把 ARKit 世界点转换成地理位置和海拔。
  • 回调里的 error 要处理,定位失败时不能保存错误锚点。
  • ARGeoAnchor(coordinate:altitude:) 适合保存用户创建的兴趣点。

Depth API:每帧读取米级深度和置信度

20:32)LiDAR 设备上,ARKit 4 暴露了 sceneDepth frame semantic。启用后,每个 ARFrame 都可以读取 ARDepthData,其中包含 depthMapconfidenceMap

// Enabling the depth API

let session = ARSession()
let configuration = ARWorldTrackingConfiguration()

// Check if configuration and device supports .sceneDepth
if type(of: configuration).supportsFrameSemantics(.sceneDepth) {
    // Activate sceneDepth
    configuration.frameSemantics = .sceneDepth
}
session.run(configuration)

...

// Accessing depth data
func session(_ session: ARSession, didUpdate frame: ARFrame) {
    guard let depthData = frame.sceneDepth else { return }
    // Use depth data
}

关键点:

  • ARWorldTrackingConfiguration() 仍然是普通世界追踪的入口。
  • supportsFrameSemantics(.sceneDepth) 检查设备是否支持 LiDAR 场景深度。
  • configuration.frameSemantics = .sceneDepth 打开深度输出。
  • frame.sceneDepth 返回 ARDepthData,其中深度像素的单位是米。
  • Session 提到深度图和相机画面长宽比一致,但分辨率更小。

人物遮挡和深度可以共用

21:12)如果 App 已经使用 personSegmentationWithDepth,支持 sceneDepth 的设备会自动提供场景深度,Session 说明这不会带来额外功耗。

// Using the depth API alongside person occlusion

let session = ARSession()
let configuration = ARWorldTrackingConfiguration()

// Set required frame semantics
let semantics: ARConfiguration.FrameSemantics = .personSegmentationWithDepth

// Check if configuration and device supports the required semantics
if type(of: configuration).supportsFrameSemantics(semantics) {
    // Activate .personSegmentationWithDepth
    configuration.frameSemantics = semantics
}
session.run(configuration)

关键点:

  • personSegmentationWithDepth 是人物遮挡所需的 frame semantic。
  • supportsFrameSemantics(semantics) 仍然是启用前的设备能力检查。
  • 开启后,App 可以继续使用人物遮挡,并在支持设备上读取 sceneDepth
  • 这适合把虚拟物体放在人和真实环境之间,增强遮挡关系。

Raycasting:用查询取代旧 hit-testing

25:41)ARKit 4 推荐用 raycasting 做物体放置。LiDAR 设备上,raycasting 会利用 scene depth 或 scene geometry,在白墙这类缺少特征的表面也能更快给出结果。

let session = ARSession()
hitTest(point, types: [.existingPlaneUsingGeometry,
                       .estimatedVerticalPlane,
                       .estimatedHorizontalPlane])

let query = arView.makeRaycastQuery(from: point,
                                    allowing: .estimatedPlane,
                                    alignment: .any)

let raycast = session.trackedRaycast(query) { results in
   // result updates
}

关键点:

  • 上半段展示旧 hitTest 写法,通常还需要开发者自己过滤多个结果。
  • makeRaycastQuery(from:allowing:alignment:) 用一个查询描述射线、目标表面和对齐方式。
  • .estimatedPlane 允许 ARKit 根据当前理解估算表面。
  • .any 允许水平和垂直等不同方向的表面。
  • trackedRaycast 会随着 ARKit 对场景理解更新而持续回调结果。

核心启发

  • 做什么:做一个户外地标导览 App,用户走到建筑附近就看到悬浮说明牌。 为什么值得做:位置锚点可以把内容绑定到经纬度,ARKit 负责视觉定位和本地坐标融合。 怎么开始:用 ARGeoTrackingConfiguration.checkAvailability 检查地点,再用 ARGeoAnchor(name:coordinate:) 放置每个地标。

  • 做什么:做一个门店或展馆的 AR 路标系统,把入口、服务台和出口标在真实空间中。 为什么值得做ARGeoTrackingStatus 会告诉你当前处于初始化、定位中还是已定位,适合引导用户举起设备看向建筑。 怎么开始:启动 geo tracking 后持续监听状态,只在 localized 且精度达标时显示导航内容。

  • 做什么:做一个 LiDAR 房间扫描预览,把每帧深度转成点云,用颜色显示真实场景。 为什么值得做frame.sceneDepth 提供 depth map 和 confidence map,Session 的示例正是把深度反投影成 3D 点云。 怎么开始:启用 .sceneDepth,在 session(_:didUpdate:) 里读取 ARDepthData,按置信度过滤低质量点。

  • 做什么:做一个更可靠的 AR 家具摆放功能,点击白墙或空地也能快速放置。 为什么值得做:ARKit 4 的 raycasting 会在可用时利用 scene depth 或 scene geometry,减少旧 hit-testing 后的自定义筛选。 怎么开始:用 arView.makeRaycastQuery(from:allowing:alignment:) 创建查询,再用 session.trackedRaycast 跟踪放置结果。

  • 做什么:做一个面部贴纸或实时表情角色功能,覆盖更多没有 TrueDepth 的设备。 为什么值得做:ARKit 4 把 Face Tracking 扩展到带前置摄像头且使用 A12 Bionic 或更新芯片的设备。 怎么开始:按设备能力检查 Face Tracking,使用 face anchors、face geometry 和 blendshapes 驱动虚拟内容。

关联 Session

评论

GitHub Issues · utterances