探索 RealityKit 的新进展
Explore advances in RealityKit
2026年6月10日
一句话判断
✅ RealityKit 正式跨过”3D 模型查看器”门槛,原生导航网格 (Navigation Mesh) 和物理空间光照 (Physical Space Lighting) 让它具备了开发重度 visionOS 空间游戏的底层基建能力。
这场 Session 讲了什么
这场 Session 最值得关注的一件事,就是 Apple 终于把游戏引擎里最脏最累的”基建”活儿给干了。以前在 visionOS 里做个稍微复杂点的 3D 游戏,NPC 寻路得自己手搓 A* 算法,虚拟物体打在真实房间墙上的光影假得让人出戏。现在 RealityKit 直接甩出了原生 NavMesh 和能让虚拟光照亮真实房间的 API。
从 API 层面看,变化非常实在。光照方面新增了 SurroundingsLight 组件,配合投影纹理 (Projective Textures),你可以做一个虚拟投影仪,把星星直接投射到玩家真实的卧室墙壁上。寻路方面,NavigationController 提供了原生的异步路径计算,还支持区域成本 (Area Costs) 和网格外连接 (Off-mesh Connections,比如爬梯子)。
这对谁影响最大?绝对是 visionOS 上的重度游戏和沉浸式叙事 App 开发者。如果你之前因为 RealityKit 缺乏寻路和高级光影而被迫去用 Unity 或 Unreal 的 PolySpatial,现在可以认真考虑回归原生生态了。
值得深挖的点
物理空间光照 (Physical Space Lighting):打破虚实边界的杀手锏
Apple 做这个功能的意图很明显:visionOS 的终极体验不是把玩家关在纯虚拟世界里,而是让虚拟内容”长”在真实环境里。以前我们只能让真实环境的光照影响虚拟物体(基于 IBL 的环境光照),现在反过来了,SurroundingsLight 组件允许虚拟光源(目前仅限 SpotLight 和 PointLight)去照亮系统捕获的真实世界网格 (Scene Understanding Mesh)。
配合新增的投影纹理,你可以实现非常惊艳的效果,比如视频里展示的虚拟天文馆,把星空直接打在真实的墙壁和家具上。设计上的 trade-off 在于,这极度依赖设备对周围环境的实时重建精度。如果玩家房间里有很多反光材质或者玻璃,环境网格会破洞,投影上去的星空就会穿模或断裂。另外,这个特性目前不支持 DirectionalLight(平行光),这意味着你没法做”虚拟太阳照亮整个真实房间”的效果,只能做局部光源。
原生 NavMesh:迟来但够用的寻路基建
在 3D 引擎里,导航网格 (Navigation Mesh) 是标配,但 RealityKit 直到今年才补齐。Apple 的设计选择非常克制且务实:没有搞大而全的实时动态 NavMesh 烘焙,而是侧重于静态网格加局部成本调整。NavigationMeshResource 负责存几何数据,NavigationComponent 负责挂载和过滤,NavigationController 负责算路。
最亮眼的设计是 computePath 是异步的 (async)。在 visionOS 这种对帧率极其敏感的平台,主线程卡 16ms 就会导致画面撕裂或眩晕,把寻路计算扔到后台是绝对正确的决定。支持”网格外连接”也是个加分项,它解决了 NavMesh 的经典痛点:两个不连通的网格(比如被悬崖隔开的两个平台)可以通过配置”梯子”或”跳跃点”连起来。不过坑在于,Session 里没有详细讲动态障碍物 (Dynamic Obstacles) 怎么实时更新 NavMesh,如果你的游戏里有大量会移动的墙体,可能还是得自己写局部避障 (Local Avoidance) 逻辑。
代码片段
1. 让虚拟光照亮真实房间
场景:做一个虚拟手电筒或投影仪,把光斑打在玩家真实的墙壁上。
// 创建一个虚拟聚光灯
let spotLightEntity = Entity()
spotLightEntity.components.set(SpotLightComponent(
color: .white,
intensity: 5000,
innerAngleInDegrees: 30,
outerAngleInDegrees: 45,
attenuationRadius: 10
))
// 开启物理空间光照,让光照亮真实环境
spotLightEntity.components.set(SpotLightComponent.SurroundingsLight())
// 可选:添加投影纹理,比如投射星星图案
let texture = try await TextureResource(named: "stars_pattern")
spotLightEntity.components.set(SpotLightComponent.ProjectiveTexture(texture: texture))
坑:SurroundingsLight 目前只支持 SpotLight 和 PointLight。如果房间太暗或者环境网格没扫描出来,光打上去会没反应。
2. 配置物理级软阴影
场景:让虚拟物体的阴影边缘变柔和,模拟真实世界中具有面积的光源(如灯箱、窗户)。
guard var shadow = hearthSpotlight.components[SpotLightComponent.Shadow.self] else {
return
}
// 设置光源的物理尺寸(米),数值越大半影(柔和边缘)越宽
shadow.lightSize = 0.7
// 设置阴影质量,medium 是性价比最高的选择
shadow.quality = .medium
hearthSpotlight.components.set(shadow)
坑:千万别把 quality 设为 .low,不管 lightSize 设多大,都会直接退化成硬阴影。.high 会显著增加 GPU 负担,中远景物体用 .medium 足矣。
3. 基于屏幕面积的 LOD (多细节层次)
场景:优化场景性能,当物体在视野中变小时,自动切换为低模。
let highDetail = [ModelEntity(mesh: highPolyMesh)]
let lowDetail = [ModelEntity(mesh: lowPolyMesh)]
let entity = Entity()
// 根据物体占据屏幕的面积比例来切换 LOD
LevelOfDetailComponent.addByScreenArea(to: entity, levels: [
(entities: highDetail, minArea: 0.05), // 占据屏幕 5% 以上用高模
(entities: lowDetail, minArea: 0.0) // 小于 5% 用低模
])
坑:相比按相机距离 (Camera Distance),按屏幕面积 (Screen Area) 在 VR/AR 中更准确,因为视野边缘的物体即使距离近,占据的像素也少。但计算屏幕面积会有微小的 CPU 开销,别给几千个碎石子都挂这个组件。
最佳实践
- 热状态管理是必修课:visionOS 散热受限,Session 里专门提了监听
ProcessInfo.thermalState。当状态变成.serious或.critical时,必须动态降低阴影质量或强制切换更激进的 LOD。别等系统把你的 App 降频卡顿了才想起来做优化。 - NavMesh 的异步陷阱:
NavigationController.computePath是 async 的,这意味着你拿到路径时,NPC 的位置可能已经变了。在写移动逻辑时,一定要把路径的第一个点设为 NPC 当前位置到路径起点的平滑过渡,否则 NPC 会瞬移。 - 新项目直接上 Reality Composer Pro 3:今年光照烘焙 (Lightmap)、NavMesh 绘制都在 RCP3 里可视化了。别在代码里硬算间接光照和手写 NavMesh 顶点,用官方工具链能省去 80% 的调试时间。
还有什么值得关注
- 3D 高斯泼溅 (3D Gaussian Splats):RealityKit 原生支持了
GaussianSplatComponent,可以直接渲染高保真的真实世界扫描数据,比传统的摄影测量 (Photogrammetry) 效果更惊艳,适合做数字孪生或沉浸式回忆场景。 - 布料模拟 (Cloth Simulation):新增了
ClothBodyComponent,支持把布料顶点钉在骨骼或锚点上(Kinematic),终于能给虚拟角色做自然飘动的披风或窗帘了。 - 自定义混响网格 (Custom Reverb Meshes):空间音频不再只靠简单的房间预设,现在可以通过
ReverbMeshResource自定义材质的吸收和散射系数,让虚拟山洞里的回声和真实房间的物理属性完美匹配。