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

What's new in RealityKit

观看原视频

Highlight

RealityKit 2020 新增 VideoMaterial、Scene Understanding、DebugModelComponent,并接入 ARKit 4 的 Face Tracking 与 Location Anchors,让 AR 内容可以播放视频纹理、感知 LiDAR 重建网格、调试渲染属性并绑定真实地理位置。


核心内容

AR 应用最难的一步,往往不是把模型放到屏幕上。真正的问题是,虚拟物体进入真实房间之后,看起来是否像在那里。它要被树干挡住,要在台阶上弹开,要在地面留下阴影,还要让开发者知道错误来自模型、材质,还是空间网格。

RealityKit 在 2019 年提供了一个面向 AR 的 3D 引擎。2020 年这场 session 把重点放在运行时能力。Apple 新增视频材质,让实体表面可以直接使用 AVPlayer 播放的视频,并自动把视频声音变成来自实体位置的空间音频。

更大的变化来自 Scene Understanding(场景理解)。RealityKit 借助 LiDAR 与 ARKit 生成的真实世界网格,把现实环境变成可遮挡、可接收阴影、可参与物理、可被射线检测的对象。开发者不再只能用平面或简单几何体近似世界。

调试也进入 RealityKit 本身。新的 DebugModelComponent 可以把法线、纹理坐标、材质参数、PBR 光照输出显示在指定实体上。它解决的是另一类常见问题:模型来自外部工具时,渲染错误到底是资源坏了,还是代码设置错了。

最后,RealityKit 跟进 ARKit 4。Face Tracking 扩展到没有 TrueDepth 摄像头但搭载 A12 或更新芯片的设备。Location Anchors 则允许用真实世界坐标创建 AR 锚点,把内容放到具体地点。


详细内容

VideoMaterial:把视频变成材质和空间音源

04:52)VideoMaterial 使用 AVFoundation 的 AVPlayer 作为视频源。开发者先创建 AVURLAssetAVPlayerItem,再把 AVPlayer 交给 RealityKit 的 VideoMaterial。材质赋给实体后,视频纹理会随播放器更新。

// Use AVFoundation to load a video
let asset = AVURLAsset(url: Bundle.main.url(forResource: "glow", withExtension: "mp4")!)
let playerItem = AVPlayerItem(asset: asset)

// Create a Material and assign it to your model entity...
let player = AVPlayer()
bugEntity.materials = [VideoMaterial(player: player)]

// Tell the player to load and play
player.replaceCurrentItem(with: playerItem)
player.play()

关键点:

  • AVURLAsset 负责从 app bundle 加载 glow.mp4
  • AVPlayerItem 把资源包装成播放器可以消费的项目。
  • VideoMaterial(player:) 把播放器输出接到 RealityKit 材质系统。
  • bugEntity.materials 把视频材质放到实体表面。
  • replaceCurrentItem(with:) 决定当前播放内容。
  • play() 启动播放,纹理开始随时间变化。

这个 API 的价值在于复用 AVFoundation。播放器仍然可以 playpauseseek,可以用 AVPlayerLooper 循环播放,也可以用 AVQueuePlayer 播放队列。session 还说明,视频材质会播放空间音频,实体会成为视频声音的空间来源。

Scene Understanding:让真实世界参与遮挡、阴影、物理和碰撞

06:53)Scene Understanding 是 ARView 的 environment 相关设置。它包含四个选项:occlusionreceivesLightingphysicscollision

使用要点:

  • .occlusion 让真实物体遮挡虚拟物体,树可以挡住虫子。
  • .receivesLighting 让真实表面接收虚拟物体投下的阴影。
  • .physics 让虚拟物体与真实世界网格发生物理交互。
  • .collision 生成碰撞事件,并允许对真实世界做 raycast(射线检测)。
  • session 明确说明,receivesLighting 会自动启用 occlusion,physics 会自动启用 collision。

使用物理时要记住四个限制。真实世界对象被视为静态且无限质量。网格会持续更新。网格只覆盖用户扫描过的区域。物理网格是近似结果,边缘不会像遮挡蒙版一样精确。开启 physics 时,collaborative sessions 不受支持。

用 HasSceneUnderstanding 找到真实世界实体

13:58)Raycast 会返回虚拟实体和真实世界实体。RealityKit 为真实世界对象创建 Scene Understanding Entity,并让这些实体符合 HasSceneUnderstanding。因此,过滤结果时只要找这个 trait。

// Get the position and forward direction of the bug in world space
let bugOrigin = bug.position(relativeTo: nil)
let bugForward = bug.convert(direction: [0, 0, 1], relativeTo: nil)

// Perform a raycast
let collisionResults = arView.scene.raycast(origin: bugOrigin, direction: bugForward)

// Get all hits against a Scene Understanding Entity
let filteredResults = collisionResults.filter { $0.entity as? HasSceneUnderstanding }

// Pick the closest one and get the collision point
guard let closestCollisionPoint = filteredResults.first?.position else {
	return
}

if length(bugOrigin - closestCollisionPoint) < safeDistance {
  // Avoid obstacle too close to object’s forward
}

关键点:

  • position(relativeTo: nil) 取得虫子在世界空间的位置。
  • convert(direction:relativeTo:) 把本地方向转换到世界空间。
  • arView.scene.raycast 沿虫子前进方向检测碰撞。
  • filter { $0.entity as? HasSceneUnderstanding } 只保留真实世界对象。
  • filteredResults.first?.position 取得最近的真实世界接触点。
  • 距离小于 safeDistance 时,可以让角色转向,避免撞上树、墙或台阶。

这段代码展示了一个实际用途:AR 角色可以根据真实物体移动。角色不需要知道树的语义,只需要对 RealityKit 提供的真实世界实体做射线检测。

用碰撞事件触发真实世界响应

14:48)碰撞事件同样依赖 HasSceneUnderstanding。事件回调里检查 entityAentityB 是否是真实世界实体。如果有,另一个实体就是发生真实世界碰撞的虚拟对象。

// Subscribe to all collision events
arView.scene.subscribe(to: CollisionEvents.Began.self) { event in
    // Get any entity if it conforms to HasSceneUnderstanding
    guard let sceneUnderstandingEntity = (event.entityA as? HasSceneUnderstanding)
                                      ?? (event.entityB as? HasSceneUnderstanding)
    else {
       // Did not collide with real world
       return
    }
    // The bug entity is the one that is not the scene understanding entity
    let bugEntity = (sceneUnderstandingEntity == event.entityA)
                   ? event.entityB : event.entityA

   // Disintegrate the bug entity

}

关键点:

  • subscribe(to: CollisionEvents.Began.self) 监听碰撞开始事件。
  • event.entityAevent.entityB 是发生碰撞的两个实体。
  • as? HasSceneUnderstanding 判断其中一方是否代表真实世界。
  • guard 失败时直接返回,说明碰撞发生在两个虚拟实体之间。
  • 条件表达式取出另一个实体,后续可以替换资源、播放动画或触发粒子效果。

session 中的示例是虫子撞到地面后解体。实际项目里,同一模式可以用于玻璃碎裂、球落地反弹、虚拟角色踩到真实台阶等交互。

用 collision group 控制是否碰撞真实世界

16:00)有些实体只需要被真实世界遮挡,不应该和真实世界发生碰撞。RealityKit 为真实世界对象新增 .sceneUnderstanding collision group,可以在 collision filter 里选择加入或排除。

// Only collide with real world
entity.collision?.filter.mask = [.sceneUnderstanding]

// Never collide with real world
entity.collision?.filter.mask = CollisionGroup.all.subtracting(.sceneUnderstanding)

关键点:

  • .sceneUnderstanding 表示 RealityKit 管理的真实世界碰撞组。
  • 第一行让实体只和真实世界碰撞。
  • 第二行从全部碰撞组里移除真实世界,避免实体撞到 LiDAR 网格。
  • RealityKit 会自动给 Scene Understanding Entity 设置碰撞组,开发者不用修改这些实体。

这也解释了为什么 Apple 要强调真实世界实体是只读的。它们由 RealityKit 创建和管理,修改组件可能导致未定义行为。

DebugModelComponent:直接看渲染管线里的属性

20:10)渲染问题经常藏在资源里。法线方向不对、纹理坐标错位、roughness 或 metallic 参数异常,都可能让模型看起来不真实。RealityKit 新增 Debug Model Component,用指定调试属性覆盖实体显示。

使用要点:

  • Debug Model Component 选择一个渲染属性作为可视化目标。
  • session 把可视化属性分成三类:vertex attributes(顶点属性)、material parameters(材质参数)、PBR outputs(基于物理渲染输出)。
  • 法线、纹理坐标、base color、roughness、metallic、diffuse lighting received、specular lighting received 都是演讲中点名的排查对象。
  • session 说明调试只作用于目标实体,不会自动继承到子实体。

如果 USDZ 里有多层实体结构,需要给每个要检查的实体单独添加这个组件。这样可以快速判断问题来自模型导入、材质设置,还是场景光照。

ARKit 4 集成:Face Tracking 和 Location Anchors

21:29)ARKit 4 把 Face Tracking 扩展到没有 TrueDepth 摄像头、但具备 A12 或更新芯片的设备。RealityKit 用户如果已经在代码或 Reality Composer 里使用 face anchors,应用可以在更多设备上工作,不需要改代码。

21:57)Location Anchors 使用真实世界坐标创建锚点。因为 ARGeoAnchorARAnchor 的子类,RealityKit 可以用已有的 anchor initializer 创建 anchor entity。

使用要点:

  • ARGeoAnchor 表示一个基于地理坐标的 ARKit 锚点。
  • RealityKit 可以基于这个 ARKit 锚点创建 anchor entity。
  • 挂在这个 anchor entity 下的虚拟内容会出现在指定真实地点。
  • session 说明 Location Anchors 使用新的 ARGeoTrackingConfiguration,需要手动配置并启动 ARView 的 session。

由于 ARGeoTrackingConfiguration 不是 world tracking configuration,Scene Understanding 等功能不会同时工作。做户外地点内容时,要把地理锚点能力和 LiDAR 场景理解能力分开设计。


核心启发

1. 做一个会躲避真实障碍的 AR 角色

  • 做什么:让虚拟宠物或游戏敌人沿着真实桌面、树干、台阶移动,并在接近障碍物时转向。
  • 为什么值得做:Scene Understanding 的 raycast 能检测真实世界实体,角色行为不再只依赖预设平面。
  • 怎么开始:开启 .collision,用 arView.scene.raycast 从角色朝向发射射线,再用 HasSceneUnderstanding 过滤真实世界结果。

2. 做一个带视频纹理的 AR 操作指南

  • 做什么:把维修步骤、健身动作或产品说明视频贴到 AR 平面或模型表面。
  • 为什么值得做:VideoMaterial 同时提供动态纹理和空间音频,说明内容可以贴在用户正在看的物体旁边。
  • 怎么开始:用 AVURLAsset 加载本地或远程视频,创建 AVPlayer,再把 VideoMaterial(player:) 赋给说明面板实体。

3. 做一个真实地形触发的破碎或反弹效果

  • 做什么:虚拟球撞到真实地面反弹,或虚拟物体砸到台阶后切换为碎片模型。
  • 为什么值得做:碰撞事件可以识别 Scene Understanding Entity,物体能够响应真实世界网格。
  • 怎么开始:开启 .physics.collision,订阅 CollisionEvents.Began,在回调里用 HasSceneUnderstanding 判断是否撞到真实世界。

4. 做一个户外地点 AR 标记

  • 做什么:在公园、校园或展会里,把说明牌、路线提示或纪念内容放到具体坐标。
  • 为什么值得做:Location Anchors 让 RealityKit 内容可以绑定真实地理位置,而不只是在当前扫描空间里漂浮。
  • 怎么开始:用 ARGeoAnchor 创建地理锚点,再用 AnchorEntity(anchor:) 挂载内容,并为 ARView 启动 ARGeoTrackingConfiguration

5. 做一个 AR 资源质检工具

  • 做什么:在内部调试菜单里切换法线、纹理坐标、材质参数和 PBR 输出可视化。
  • 为什么值得做:DebugModelComponent 可以直接暴露模型渲染属性,适合排查 USDZ 导入和材质设置问题。
  • 怎么开始:给当前选中的 ModelEntity 设置 DebugModelComponent,对多层 USDZ 递归给需要检查的子实体添加组件。

关联 Session

评论

GitHub Issues · utterances