WWDC Quick Look 💓 By SwiftGGTeam
Explore object tracking for visionOS

Explore object tracking for visionOS

观看原视频

Highlight

Object Tracking 是 visionOS 今年推出的全新能力,它让你的 app 能够识别和追踪真实世界中的具体物体——你桌上的那个地球仪、那台显微镜——并把虚拟内容锚定在上面。之前的锚点类型只支持平面、图像和手,Object Tracking 把真实物体本身变成了锚点。演示中,一个真实的地球仪被虚拟卫星环绕,点击后还能看到地核的剖面图——虚拟的月球和空间站会消失在真实地球仪的背后,营造出强烈的沉浸感。


核心内容

在 visionOS 上做空间体验,你之前能锚定的东西有限:平面、图像、手。如果你的虚拟内容需要”附着”在某个具体的真实物体上——比如让卫星绕着一个真实的地球仪飞——你就只能用平面锚点近似,位置不精确,也没有遮挡效果。

Object Tracking 解决了这个问题。它让你把真实物体本身变成锚点。系统通过机器学习模型识别物体,持续输出它的位置、朝向和边界框。你的虚拟内容可以精确地附着在物体表面,甚至能被真实物体遮挡——虚拟卫星飞到地球仪背面时会消失,就像真的绕过去了。

整个工作流分三步:第一步,提供目标物体的 USDZ 3D 模型(越逼真越好,可以用 Object Capture 从 iPhone 扫描生成)。第二步,在 Create ML app 中训练一个机器学习模型,输出一个 .referenceobject 文件。第三步,在你的 visionOS app 中加载这个 reference object,启动追踪,锚定虚拟内容。

苹果把这个能力设计得相对平易近人——Create ML 提供了可视化的训练界面,拖入 USDZ 文件就能开始训练,全程本地运行在你的 Mac 上。但也有一些明确的限制:物体必须是刚性(rigid)的、非对称的、基本静止的,而且需要逐个物体训练 ML 模型。训练过程可能需要数小时,且仅支持 Apple Silicon Mac。


详细内容

创建 Reference Object

训练的输入是一个 USDZ 格式的 3D 模型。苹果建议模型尽量接近物体的真实外观,本质上需要一个”数字孪生”。最简单的获取方式是用 iPhone/iPad 上的 Object Capture 技术扫描物体(03:47)。对于有光泽或透明部件的物体,也可以提供多材质的 USDZ 资产(03:58)。

物体需要满足三个条件(04:16):

  • 大部分时间静止不动
  • 形状和纹理都是刚性的
  • 非对称——从各个角度看起来不一样

在 Create ML 中,今年新增了”Spatial”分类下的 Object Tracking 模板。配置时有一步很关键:选择观看角度(06:52)。三种选项:

  • All Angles:物体可从任意角度看到(如可旋转的地球仪),要求物体各角度外观都独特
  • Upright:物体竖直放置在桌面上(如显微镜),排除底部视角
  • Front:物体竖直放置且无需追踪背面(如示波器),排除背面和底部

选择正确的观看角度对追踪质量影响很大,因为它指导 ML 训练关注哪些视角。

在 Reality Composer Pro 中锚定内容

训练完成后,在 Reality Composer Pro 中创建一个 Transform Entity,添加 AnchoringComponent,选择新的”Object”目标类型,然后关联你的 reference object(10:18)。视口中会出现半透明的 USDZ 模型预览,帮助你精确放置虚拟内容——比如在地球仪上的卡纳维拉尔角位置放置太空梭发射实体。

要实现”虚拟被真实遮挡”的效果,需要在 Anchor Entity 下添加一个 USDZ 地球仪实体作为遮挡体,并在 ShaderGraph 编辑器中给它应用 Occlusion Material(11:55)。当 Object Tracking 更新父锚点的 transform 时,遮挡体会与真实地球仪对齐,绕行的虚拟物体经过它后面时自然消失。

用 RealityKit API 实现 Coaching UI

当用户还没找到目标物体时,app 需要一个引导界面(Coaching UI)。第一步是显示物体的预览模型(13:55):

// Display object USDZ
struct ImmersiveView: View {
   @State var globeAnchor: Entity? = nil
    var body: some View {
        RealityView { content in
            // Load the reference object with ARKit API
            let refObjURL =
            Bundle.main.url(forResource: "globe", withExtension: ".referenceobject")
            let refObject = try? await ReferenceObject(from: refObjURL!)

            // Load the model entity with USDZ path extracted from reference object
            let globePreviewEntity =
            try? await Entity.init(contentsOf: (refObject?.usdzFile)!)

            // Set opacity to 0.5 and add to scene
            globePreviewEntity!.components.set(OpacityComponent(opacity: 0.5))
            content.add(globePreviewEntity!)
        }
    }
}

关键点:

  • ReferenceObject(from:) 通过 ARKit API 加载 .referenceobject 文件
  • refObject?.usdzFile 从 reference object 中提取原始 USDZ 路径,用于加载预览模型
  • OpacityComponent(opacity: 0.5) 设置半透明,表示这只是预览而非实际追踪结果

第二步,监听锚点状态变化(14:13):

// Check anchor state
struct ImmersiveView: View {
   @State var globeAnchor: Entity? = nil
    var body: some View {
        RealityView { content in
            if let scene = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
                globeAnchor = scene.findEntity(named: "GlobeAnchor")
                content.add(scene)
            }
            let updateSub = content.subscribe(to: SceneEvents.AnchoredStateChanged.self) { event in
                if let anchor = globeAnchor, event.anchor == anchor {
                    if event.isAnchored {
                        // Object anchor found, trigger transition animation
                    } else {
                        // Object anchor not found, display coaching UI
                    }
                }
            }
        }
    }
}

关键点:

  • SceneEvents.AnchoredStateChanged 事件在锚点状态变化时触发
  • event.isAnchored 为 true 表示物体已被追踪到,为 false 表示丢失
  • 根据 isAnchored 状态切换显示 coaching UI 或触发过渡动画

第三步,获取追踪物体的空间变换用于过渡动画(14:31):

// Transform space
struct ImmersiveView: View {
   @State var globeAnchor: Entity? = nil
    var body: some View {
        RealityView { content in
            // Setup anchor transform space for object and world anchor
            let trackingSession = SpatialTrackingSession()
            let config = SpatialTrackingSession.Configuration(tracking: [.object, .world])
            if let result = await trackingSession.run(config) {
                if result.anchor.contains(.object) {
                    // Tracking not authorized, adjust experience accordingly
                }
            }
           // Get tracked object's world transform, identity if tracking not authorized
            let objectTransform = globeAnchor?.transformMatrix(relativeTo: nil)
            // Implement animation
            ...
        }
    }
}

关键点:

  • SpatialTrackingSession.Configuration(tracking: [.object, .world]) 请求 object 和 world 追踪权限
  • result.anchor.contains(.object) 检查 object 追踪是否被授权
  • transformMatrix(relativeTo: nil) 获取锚点在世界坐标系中的变换矩阵,未授权时返回 identity

新增的 ARKit API

苹果今年还发布了配套的 ARKit Object Tracking API(15:45),提供追踪物体的边界框和对应 USDZ 文件的访问,以及追踪就绪状态和异常事件的通知。配套的示例 app 可从开发者文档下载。


核心启发

  • 做什么:教育类 app 中给教具叠加虚拟标注。为什么值得做:学生用 Apple Vision Pro 看真实显微镜时,虚拟标签可以标注各部件名称和功能,比纸质说明书直观得多。怎么开始:用 Object Capture 扫描教具生成 USDZ,在 Create ML 中训练 reference object,用 RealityKit 锚定 SwiftUI 标签。

  • 做什么:产品展示中让实物触发沉浸式体验。为什么值得做:消费者在门店拿起产品时,虚拟动画和功能演示直接在产品上播放,比看屏幕上的视频更有代入感。怎么开始:选择”Front”或”Upright”观看角度训练模型(产品通常竖直放置),用 Occlusion Material 让虚拟内容在产品背面消失。

  • 做什么:工业场景中给设备叠加虚拟操作指引。为什么值得做:维修人员面对复杂设备时,虚拟箭头和高亮区域直接标注在设备上,减少翻阅手册的时间。怎么开始:用 Coaching UI 的模式——先显示设备预览引导用户找到目标,追踪到后切换为操作指引覆盖层,监听 AnchoredStateChanged 事件管理状态切换。


关联 Session

评论

GitHub Issues · utterances