WWDC Quick Look 💓 By SwiftGGTeam
What’s new in RealityKit

What’s new in RealityKit

观看原视频

Highlight

RealityKit 2025 把 ARKit 数据通过 AnchorStateEvents 直接暴露给应用,并用 ManipulationComponent.configureEntity() 一行代码完成 3D 物体的抓取、旋转与双手交接。

核心内容

过去做一个能放在桌面上、可以伸手抓取、又能正确被现实物体遮挡的小游戏,开发者要同时管 ARKit session、RealityKit 场景、自定义手势识别、物理状态切换。一套流程下来,胶水代码远多于业务代码。今年 RealityKit 把这些环节直接做进了框架。

Laurence 用一个空间解谜游戏把所有新特性串了起来:宝箱锚定在桌面上,玩家抓起周围的小物件去找钥匙,找到后宝箱打开放出小烟花。游戏里用到的能力,恰好覆盖了 RealityKit 2025 的更新清单——SpatialTrackingSession 直接产生 AnchorStateEventsManipulationComponent 接管抓取交互,SceneUnderstandingFlags 让真实房间网格参与物理模拟,EnvironmentBlendingComponent 让虚拟物体被现实静态物遮挡,MeshInstancesComponent 用 GPU instancing 高效渲染装饰物,ImagePresentationComponentVideoPlayerComponent 处理空间照片和沉浸式视频。另外,RealityKit 今年开始支持 tvOS,覆盖所有代次的 Apple TV 4K。

详细内容

ARKit 数据直通 RealityKit。 以前要并行跑 ARKit session 和 RealityKit 场景,现在通过 SpatialTrackingSession 启动追踪,再用 AnchorEntity 描述要找什么样的锚点,命中后通过 AnchorStateEvents.DidAnchor 直接拿到 ARKit 原始数据(04:33)。

// Set up SpatialTrackingSession
@State var spatialTrackingSession = SpatialTrackingSession()

RealityView { content in
    let configuration = SpatialTrackingSession.Configuration(
        tracking: [.plane]
    )
    if let unavailableCapabilities = await spatialTrackingSession.run(configuration) {
        // Handle errors
    }
}

关键点:

  • SpatialTrackingSession.Configurationtracking: [.plane] 声明只追踪平面,按需开关能减少耗电。
  • run(configuration) 是 async 方法,返回值为 unavailableCapabilities,里面是当前设备不支持的能力,开发者要在这里降级。
  • session 必须放在 RealityView 的闭包里启动,确保和当前 immersive scene 同生命周期。

拿到锚点事件后,可以直接 cast 到 ARKit 的 PlaneAnchor 用原生 transform(05:48):

didAnchor = content.subscribe(to: AnchorStateEvents.DidAnchor.self) { event in
    guard let anchorComponent =
        event.entity.components[ARKitAnchorComponent.self] else { return }
    guard let planeAnchor = anchorComponent.anchor as? PlaneAnchor else { return }

    let worldSpaceFromExtent =
        planeAnchor.originFromAnchorTransform *
        planeAnchor.geometry.extent.anchorFromExtentTransform

    gameRoot.transform = Transform(matrix: worldSpaceFromExtent)
    // Add game objects to gameRoot
}

关键点:

  • event.entity.components[ARKitAnchorComponent.self] 是 RealityKit 新加的桥接组件,承载 ARKit 原始锚点。
  • anchorComponent.anchor 类型为 ARAnchor,需要按业务需要 cast 到 PlaneAnchorImageAnchor 等具体类型。
  • originFromAnchorTransform * anchorFromExtentTransform 把游戏根节点对齐到平面 extent 的中心,避免模型半截悬空。

ManipulationComponent 接管抓取。 一行 ManipulationComponent.configureEntity() 就能让任意 entity 支持抓取、旋转,甚至双手交接(07:38):

extension Entity {
    static func loadModelAndSetUp(modelName: String,
                                  in bundle: Bundle) async throws -> Entity {
        let entity = // Load model and assign PhysicsBodyComponent
        let shapes = // Generate convex shape that fits the entity model

        ManipulationComponent.configureEntity(entity, collisionShapes: [shapes])
        var manipulationComponent = ManipulationComponent()
        manipulationComponent.releaseBehavior = .stay
        entity.components.set(manipulationComponent)
        return entity
    }
}

关键点:

  • configureEntity 内部一次性挂载 InputTargetComponentCollisionComponentHoverEffectComponentManipulationComponent,省掉手动配置。
  • releaseBehavior = .stay 让物体松手后留在原地,默认值会自动飘回起点,不适合解谜场景。
  • 抓取时机要配合 ManipulationEvents 切换物理模式(09:28),抓起时设 kinematic,松手时设 dynamic 让重力接管。

Scene Understanding 参与物理模拟。SpatialTrackingSession.Configuration 里加上 sceneUnderstanding: [.collision, .physics]10:52),房间真实网格直接进入物理世界,物体掉到地上会被真地板接住。

EnvironmentBlendingComponent 处理静态遮挡。 preferredBlendingMode: .occluded(by: .surroundings)11:56)让虚拟实体被真实静态物体精确遮挡,但人和宠物等动态对象不参与遮挡。挂了这个组件的实体会被当成背景层,永远绘制在其他虚拟物体后面。

MeshInstancesComponent 大批量装饰物。 用一个 entity 加一组 transform 矩阵就能渲染上百个相同模型(14:20),相比克隆 entity 在内存占用和 draw call 上都省得多。LowLevelInstanceData(instanceCount:) 给出可写入的 transform 缓冲。

ImagePresentationComponent 处理三种图像。 普通 2D 图片、spatial photo、以及由 2D 图片生成的 spatial scene。设 desiredViewingMode 之前要先用 availableViewingModes.contains(.spatialStereo) 检查(17:57),否则会回退到 2D。spatial scene 通过 ImagePresentationComponent.Spatial3DImagegenerate() 生成,效果与系统 Photos app 一致。

VideoPlayerComponent 扩展。 支持 spatial video 完整空间样式、APMP 180/360/Wide-FOV、Apple Immersive Video,并自动调节舒适度。

Entity 直接从 Data 加载。 Entity(from: data) 让模型可以从网络流直接构造(23:35),不用再先落盘再加载。

核心启发

  1. 把 ARKit 接入 RealityKit 当默认起手式。新建空间项目时,直接用 SpatialTrackingSession + AnchorStateEvents 取代手动维护的 ARKit session。为什么值得做:少一份并行的状态管理,锚点生命周期与 entity 生命周期天然绑定。怎么开始:把现有 ARSession.run 替换为 SpatialTrackingSession.run,订阅 DidAnchor/WillUnanchor/DidFailToAnchor 三个事件。

  2. 用 ManipulationComponent 替换自写的拖拽手势。为什么值得做:双手交接、惯性、视觉 hover 效果都是免费送的,自己实现要写几百行手势代码。怎么开始:找到项目里所有 DragGesture/SpatialTapGesture 处理 3D 物体的地方,换成 ManipulationComponent.configureEntity(entity, collisionShapes:),再用 ManipulationEvents.WillBegin/WillEnd 切换 PhysicsBodyComponent.mode

  3. 打开 Scene Understanding 的 collision/physics 标志。为什么值得做:让虚拟物体真的能”放在”现实桌子上,比手动检测平面再做碰撞稳定得多。怎么开始:在 SpatialTrackingSession.Configuration 里加 sceneUnderstanding: [.collision, .physics],给会落地的物体配 PhysicsBodyComponent(mode: .dynamic)

  4. 用 MeshInstancesComponent 渲染场景装饰。为什么值得做:克隆 entity 在 visionOS 上 draw call 涨得很快,instancing 在几十上百个实例时帧率明显更稳。怎么开始:把重复的 Entity.clone(recursive:) 改成 MeshInstancesComponent,用 LowLevelInstanceData.withMutableTransforms 批量写 transform 矩阵。

  5. 检查 availableViewingModes 后再设 desiredViewingMode。为什么值得做:spatial photo 不一定支持每种 viewing mode,盲设会静默回退。怎么开始:所有 ImagePresentationComponent 的初始化代码加一道 availableViewingModes.contains(...) 守卫。

关联 Session

评论

GitHub Issues · utterances