WWDC Quick Look 💓 By SwiftGGTeam
Create enhanced spatial computing experiences with ARKit

Create enhanced spatial computing experiences with ARKit

观看原视频

Highlight

ARKit 在 visionOS 2.0 新增 Room Tracking,把原来只有几何顶点的 mesh 数据升级为带有房间边界语义的 RoomAnchor,让应用可以按房间切换虚拟内容。


核心内容

做 visionOS 应用的开发者都会碰到一个问题:ARKit 给你一堆 mesh 顶点和平面锚点,但你的代码没法判断”用户现在在哪个房间”。你只能靠坐标和几何去猜,猜错了虚拟内容就放错地方。Super Fruit Ninja 之所以能把水果残渣溅到地板上,靠的是 scene understanding,但去年的 API 只能识别平面和 mesh,做不到”房间”级别的语义。

今年 ARKit 加入了 Room Tracking,直接告诉你用户当前所在房间的边界、墙壁和地板几何体,还能在用户从客厅走到卧室时自动切换数据源。同时新增的 Object Tracking 允许你用 USDZ 模型注册一个真实物体,ARKit 持续追踪它的位置和朝向,适合教育、工业这类需要在真实物品上叠加虚拟内容的场景。Plane Detection 也补上了 Slanted 对齐方式,能检测斜面了。此外,World Tracking 在暗光环境下会自动降级为仅朝向追踪,Hand Tracking 则支持了 display-rate 输出和手部预测,降低了交互延迟。


详细内容

Room Tracking

RoomTrackingProvider 是今年新增的 DataProvider,需要 world sensing 授权。它能提供当前房间的 RoomAnchor,以及异步的 anchor 更新序列(03:35)。

// RoomTrackingProvider

@available(visionOS, introduced: 2.0)
public final class RoomTrackingProvider: DataProvider, Sendable {

    /// The room which a person is currently in, if any.
    public var currentRoomAnchor: RoomAnchor? { get }

    /// An async sequence of all anchor updates.
    public var anchorUpdates: AnchorUpdateSequence<RoomAnchor> { get }

    ...
}

关键点:

  • currentRoomAnchor 直接返回当前房间的锚点,为 nil 时说明 ARKit 没有识别到封闭空间
  • anchorUpdates 是异步序列,适合监听房间切换事件
  • RoomTrackingProvider 只更新当前所在房间的 anchor 数据,不会同时更新所有历史房间

每个 RoomAnchor 包含房间的几何信息(04:20):

@available(visionOS, introduced: 2.0)
public struct RoomAnchor: Anchor, Sendable, Equatable {
    /// True if this is the room which a person is currently in.
    public var isCurrentRoom: Bool { get }

    /// Get the geometry of the mesh in the anchor's coordinate system.
    public var geometry: MeshAnchor.Geometry { get }
    /// Get disjoint mesh geometries of a given classification.
    public func geometries(of classification: MeshAnchor.MeshClassification) ->
        [MeshAnchor.Geometry]

    /// True if this room contains the given point.
    public func contains(_ point: SIMD3<Float>) -> Bool

    /// Get the IDs of the plane anchors associated with this room.
    public var planeAnchorIDs: [UUID] { get }
    /// Get the IDs of the mesh anchors associated with this room.
    public var meshAnchorIDs: [UUID] { get }
}

关键点:

  • isCurrentRoom 判断该锚点是否代表用户当前所在房间,用于按房间切换虚拟内容
  • geometry 返回的 mesh 比普通 mesh anchor 更贴合房间边界
  • geometries(of:) 按分类(墙/地板)返回分离的几何体,适合做遮挡或整面墙的虚拟传送门
  • contains(_:) 可以判断一个 3D 点是否在房间内,配合 world tracking 可以实现”走进某房间才触发”的效果
  • planeAnchorIDsmeshAnchorIDs 让你可以过滤出属于当前房间的锚点,避免对房间外的数据做昂贵的计算

Object Tracking

Object Tracking 需要先通过 CreateML 生成 ReferenceObject,然后在运行时加载并启动追踪(08:06)。

// Object tracking

Task {
    do {
        let url = URL(fileURLWithPath: "/path/to/globe.referenceobject")
        let referenceObject = try await ReferenceObject(from: url)
        let objectTracking = ObjectTrackingProvider(referenceObjects: [referenceObject])
    } catch {
        // Handle reference object loading error.
    }
    ...
}

关键点:

  • ReferenceObject 从文件 URL 加载,也可以从 Bundle 加载
  • 一个 ObjectTrackingProvider 可以同时追踪多个 ReferenceObject
  • 加载失败会抛异常,需要 catch 处理

启动 session 并监听状态(08:27):

let session = ARKitSession()

Task {
    do {
        try await session.run([objectTracking])
    } catch {
        // Handle session run error.
    }

    for await event in session.events {
        switch event {
        case .dataProviderStateChanged(_, newState: let newState, _):
            if newState == .running {
                // Ready to start processing anchor updates.
            }
        ...
        }
    }
}

关键点:

  • session.run() 是 async 的,需要 await
  • DataProvider 进入 .running 状态后才能处理 anchor 更新
  • 通过 session.events 异步监听状态变化

追踪结果以 ObjectAnchor 形式返回(08:43):

// ObjectAnchor

@available(visionOS, introduced: 2.0)
public struct ObjectAnchor: TrackableAnchor, Sendable, Equatable {

    /// An axis-aligned bounding box.
    public struct AxisAlignedBoundingBox: Sendable, Equatable {
        ...
    }

    /// The bounding box of this anchor.
    public var boundingBox: AxisAlignedBoundingBox { get }

    /// The reference object which this anchor corresponds to.
    public var referenceObject: ReferenceObject { get }
}

关键点:

  • boundingBox 提供检测到物体的轴对齐包围盒,可以获取 center、extent、最小/最大坐标
  • referenceObject 指向匹配的 ReferenceObject,可从中获取原始 USDZ 文件路径
  • Object Tracking 只能追踪静态放置的物体,不能追踪运动中的物体

World Tracking 光照降级

暗光环境下,ARKit 自动从完整追踪降级为仅朝向追踪。SwiftUI 新增了 worldTrackingLimitations 环境值来通知应用(11:03):

struct WellPreparedView: View {
    @Environment(\.worldTrackingLimitations) var worldTrackingLimitations

    var body: some View {
        ...

        .onChange(of: worldTrackingLimitations) {
            if worldTrackingLimitations.contains(.translation) {
                // Rearrange content when anchored positions are unavailable.
            }
        }
    }
}

关键点:

  • .translation 出现在 limitations 中,说明位置追踪已不可用,只剩朝向追踪
  • 可以在此回调中重新排列已放置的虚拟内容,或提示用户移到更亮的环境
  • 系统层面已经自动降级为朝向追踪,不会完全丢失追踪

Hand Tracking 预测

HandTrackingProvider 现在以 display rate 输出数据。同时新增手部预测 API,可以在 Compositor Services 渲染场景中提前预测手的位置(12:51):

// Hands prediction

func submitFrame(_ frame: LayerRenderer.Frame) {
    ...

    guard let drawable = frame.queryDrawable() else { return }

    // Get the trackable anchor time to target.
    let trackableAnchorTime = drawable.frameTiming.trackableAnchorTime

    // Convert the timestamp into units of seconds.
    let anchorPredictionTime = LayerRenderer.Clock.Instant.epoch.duration(to:
        trackableAnchorTime).timeInterval

    // Predict hand anchors for the time that provides best content registration.
    let (leftHand, rightHand) = handTracking.handAnchors(at: anchorPredictionTime)

    ...
}

关键点:

  • trackableAnchorTime 是 visionOS 2.0 新增的时间戳,代表最佳内容对齐时刻
  • 将其转换为秒数后传给 handAnchors(at:),ARKit 会做前向预测
  • 预测结果延迟更低,但精度会有所牺牲,适合需要紧密贴合手部的场景
  • 如果对精度要求高而对延迟不敏感(如手势检测、绘画),用 display-rate 的异步更新更好

核心启发

  1. 基于房间的体验切换:用 RoomTrackingProvider 的 isCurrentRoomcontains(_:) 为每个房间定制不同的虚拟内容。为什么值得做:用户对”走到不同房间看到不同东西”的体验有直觉期待,这比手动按坐标分区更可靠。怎么开始:在 Full Space 中启用 RoomTrackingProvider,监听 anchorUpdates,切换时替换场景内容。

  2. 真实物体叠加虚拟信息:用 Object Tracking 在工业设备、教学模型、桌游配件上叠加 3D 标注或动画。为什么值得做:教育、维修、博物馆场景天然需要”对着实物看讲解”的交互,目前 visionOS 上这类应用还很少。怎么开始:用 CreateML 训练 ReferenceObject,放入 ObjectTrackingProvider 运行,用 ObjectAnchor 的 boundingBox 定位叠加位置。

  3. 暗光环境优雅降级:监听 worldTrackingLimitations,在位置追踪丢失时自动把虚拟内容从锚定模式切换为跟随视角模式。为什么值得做:用户不会总是待在灯光明亮的环境,不做降级处理就会看到内容漂移或消失。怎么开始:在 SwiftUI 视图中 .onChange(of: worldTrackingLimitations) 检测 .translation 限制,触发内容重排逻辑。

  4. 低延迟手部交互:对需要手部紧密贴合的场景(如抓取虚拟物体),使用手部预测 API 而非默认的异步更新。为什么值得做:异步 HandAnchor 有固有延迟,手快的时候虚拟物体会”跟不上手”,预测可以缩小这个差距。怎么开始:在 Compositor Services 渲染循环中用 drawable.frameTiming.trackableAnchorTime 获取目标时间,调用 handAnchors(at:) 获取预测结果。


关联 Session

评论

GitHub Issues · utterances