Highlight
RealityKit on visionOS adds custom image-based lighting, grounding shadows, tone mapping control, and dynamic content scaling — giving developers precise control over how 3D content looks and performs in spatial computing.
核心内容
你在 iOS 和 macOS 上已经用 RealityKit 做过 3D 应用。光照、材质、阴影,这些概念你都熟悉。但把同样的内容放到 visionOS 上,会发现一些微妙的差异:系统默认的光照可能不符合你的场景氛围,3D 物体悬浮在空中没有扎根感,UI 颜色和 3D 材质的颜色对不上,边缘区域的模型还会闪烁。
这场演讲从四个维度解决这些问题:光照与阴影、材质与色调映射、光栅化率映射的性能优化、以及动态内容缩放的清晰度保证。
自定义光照:Image-Based Lighting
RealityKit 使用 image-based lighting(IBL)让 3D 内容看起来真实。IBL 由两部分组成:ARKit 提供的环境探针纹理(反映真实房间的光照)和系统自带的 IBL 纹理(确保任何环境下内容都好看)。两者相加形成最终的 IBL。
(02:29)visionOS 新增了覆盖系统 IBL 的能力。你可以加载自定义的环境资源,让 3D 物体被特定的光照环境照亮。比如一个太阳系展示应用,可以用”阳光”环境资源让卫星模型沐浴在恒星光照中。
阴影:Grounding Shadow
3D 物体放在平面上时,如果没有阴影,用户很难判断它的相对高度。一个花瓶悬浮在平面中央,看起来像是飘着的。
(04:16)添加 GroundingShadowComponent 并设置 castsShadow: true 后,物体会向下方投射阴影。这个阴影不仅出现在 3D 模型上,也会投射到真实环境的物体表面。用户一眼就能看出花瓶在平面之上。
材质与色调映射
RealityKit 在 visionOS 上支持所有 iOS/macOS 的材质类型:PhysicallyBasedMaterial、SimpleMaterial、UnlitMaterial、VideoMaterial,以及新增的 ShaderGraphMaterial。
(06:34)所有材质的默认输出都会经过 tone mapping。Tone mapping 将超过 1.0 的颜色值重新映射到可见范围,让高亮区域保留更多细节。比如一个电视屏幕的纹理,开启 tone mapping 后花瓣的亮部细节会更清晰。
但有些场景需要精确的颜色匹配。比如一个交通灯应用,3D 模型的灯颜色需要和 SwiftUI 按钮的颜色完全一致。UnlitMaterial 虽然不受光照影响,但输出仍然经过 tone mapping,导致与 SwiftUI 颜色有细微差异。
(08:48)UnlitMaterial 新增了 applyPostProcessToneMap 参数,设为 false 即可关闭 tone mapping,实现与 SwiftUI UI 元素的精确颜色匹配。
光栅化率映射
visionOS 的显示屏分辨率很高,系统需要每秒更新多次。为了节省性能,系统使用了 rasterization rate map 技术:根据用户注视的位置,在视野中心使用高分辨率渲染,在边缘区域使用低分辨率。
(10:27)这个优化在 RealityKit 中自动启用,但某些内容可能需要调整。演讲者展示了一个棕榈叶模型,当眼睛看向屏幕右侧时,左侧的棕榈叶出现闪烁。原因是模型使用了大量小三角形,在边缘低分辨率区域产生了 aliasing。
(12:14)解决方案是增大小三角形、将细节存储在透明度纹理中。RealityKit 会自动为纹理生成 mipmap,在低分辨率区域使用合适的级别,消除闪烁。
动态内容缩放
SwiftUI 和 UIKit 应用在 visionOS 上自动受益于 dynamic content scaling。系统根据用户注视位置,以不同分辨率栅格化 UI 内容——注视区域最高清,周围稍低,边缘最低。
(15:34)如果使用 Core Animation 直接构建 UI,需要手动启用:设置 CALayer.wantsDynamicContentScaling = true。这个技术依赖高分辨率栅格化,不适合以位图为主的内容。
详细内容
自定义 Image-Based Lighting
RealityView { content in
async let satellite = Entity(named: "Satellite", in: worldAssetsBundle)
async let environment = EnvironmentResource(named: "Sunlight")
if let satellite = try? await satellite, let environment = try? await environment {
content.add(satellite)
satellite.components.set(ImageBasedLightComponent(
source: .single(environment)))
satellite.components.set(ImageBasedLightReceiverComponent(
imageBasedLight: satellite))
}
}
关键点:
EnvironmentResource(named:)加载自定义环境光照资源ImageBasedLightComponent指定 IBL 来源,替换系统默认 IBLImageBasedLightReceiverComponent让实体接收该 IBL 的光照- 可以将 receiver component 添加到其他实体上,让它们共享同一套光照
添加 Grounding Shadow
RealityView { content in
if let vase = try? await Entity(named: "flower_tulip") {
content.add(vase)
vase.components.set(GroundingShadowComponent(castsShadow: true))
}
}
关键点:
GroundingShadowComponent(castsShadow: true)启用阴影投射- 阴影会投射到 3D 模型和真实环境物体上
- 只需一行代码,无需手动配置光源或阴影贴图
关闭 Tone Mapping 实现精确颜色
RealityView { content in
if let trafficLight = try? await Entity(named: "traffic_light") {
content.add(trafficLight)
if let lamp = trafficLight.findEntity(named: "red_light") {
if var model = lamp.components[ModelComponent.self] {
let material = UnlitMaterial(
color: .init(color),
applyPostProcessToneMap: false // 关闭色调映射
)
model.materials = [material]
lamp.components[ModelComponent.self] = model
}
}
}
}
关键点:
applyPostProcessToneMap: false关闭材质的后处理色调映射- 适用于需要与 SwiftUI UI 颜色精确匹配的场景
- 也适用于 HUD、菜单等需要显示精确颜色的场景
- 该参数在 Reality Composer Pro 的材质编辑器中也已暴露
启用 Dynamic Content Scaling
// 在 Core Animation 的 CALayer 上启用
layer.wantsDynamicContentScaling = true
关键点:
- SwiftUI 和 UIKit 应用自动启用,无需额外操作
- Core Animation 构建的 UI 需要手动设置
wantsDynamicContentScaling - 依赖高分辨率栅格化,不适合以位图为主的内容
- 系统会根据注视位置自动调整不同区域的渲染分辨率
核心启发
1. 为 3D 展示应用添加场景专属光照
如果你的应用展示艺术品、汽车、家具等 3D 模型,默认的系统 IBL 可能无法突出产品特点。准备几套环境光照资源(studio 灯光、自然光、暖色调光),让用户切换。入口:EnvironmentResource + ImageBasedLightComponent。
2. 所有放置于表面的 3D 物体都加 Grounding Shadow
没有阴影的 3D 物体会显得漂浮不定,破坏沉浸感。无论是一个虚拟键盘、一个 3D 图标还是一个游戏角色,只要它站在某个表面上,就加上 GroundingShadowComponent。入口:一行代码 .set(GroundingShadowComponent(castsShadow: true))。
3. 构建颜色精确的设计工具
如果你在做设计类应用(如 3D 建模、材质预览、色彩工具),用户需要看到”这个红色就是 #FF0000”。关闭 tone mapping,使用 UnlitMaterial 显示精确颜色,并在旁边用 SwiftUI 的 Color 视图做对照。入口:UnlitMaterial(color:applyPostProcessToneMap: false)。
4. 优化 3D 资产以适应 Rasterization Rate Map
检查你的 3D 模型是否使用了大量微小三角形(小于一个像素)。如果是,合并小三角形、将镂空细节转移到透明度纹理中。这样模型在视野边缘的低分辨率区域不会闪烁。入口:在 Reality Composer Pro 中查看模型的三角形统计,参考 “Rendering at Different Rasterization Rates” 文档。
关联 Session
- Build great games for spatial computing — 了解 visionOS 游戏开发的渲染、音频和输入特性,包括沉浸等级选择和 RealityKit 的使用
- Meet RealityKit Trace — 使用 Instruments 分析 RealityKit 渲染性能,识别 GPU 瓶颈和优化机会
- Create 3D models for Quick Look spatial experiences — 创建适合 visionOS 的 3D 内容的最佳实践,包括几何体优化和材质设置
评论
GitHub Issues · utterances