WWDC Quick Look 💓 By SwiftGGTeam
Explore rendering for spatial computing

Explore rendering for spatial computing

观看原视频

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:48UnlitMaterial 新增了 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 来源,替换系统默认 IBL
  • ImageBasedLightReceiverComponent 让实体接收该 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

评论

GitHub Issues · utterances