What's new in Metal rendering for immersive apps
2025年6月9日
一句话判断
Metal immersive 渲染今年加了四样东西:hover effects 让交互对象有视觉反馈、动态渲染质量按场景复杂度调分辨率、progressive immersion 用 stencil 裁剪门户外的像素、Mac 可以直接渲染 immersive content 流式投射到 Vision Pro。最后一个是最大的玩法变化。
这场 Session 讲了什么
Ricardo 从 render loop 的 API 变化开始,逐步展开了今年 Compositor Services 的所有新能力。
新 Render Loop API:queryDrawables。 以前 queryDrawable 返回单个 drawable,现在 queryDrawables 返回数组。大多数时候数组只有一个元素,但当你用 Reality Composer Pro 录制高质量视频时,会返回两个 drawable——一个用于 Vision Pro 显示(.builtIn),一个用于录制(.capture)。
Hover Effects(悬停效果)。 在 drawable 上新增了 tracking areas texture。你给每个可交互对象注册一个 tracking area(带唯一 ID),如果对象有 hover effect,系统会在用户注视它时自动在 color texture 上叠加高亮效果。实现步骤:1)配置 layer 的 tracking areas texture 为 8-bit 格式(最多 255 个并发交互对象);2)注册 tracking area 并设置 .automatic 属性;3)在 fragment shader 中输出 tracking area render value 到 color attachment 1。注意 MSAA 场景:tracking areas texture 不能用常规 multisample resolve(会平均化 render value),需要自定义 tile resolver(取采样窗口中出现最频繁的值)。
Dynamic Render Quality(动态渲染质量)。 基于 foveated rendering,现在你可以控制帧级别的渲染质量。设置 maxRenderQuality 定义上限,运行时根据场景复杂度调整。更高的质量扩大高相关区域(fovea),但也增加内存和功耗。文本/UI 用高质量(.8),复杂 3D 场景降质量(.6)。系统会平滑过渡质量值。
Progressive Immersion(渐进式沉浸)。 新的 immersion style,用户转动 Digital Crown 调节沉浸程度。系统提供 portal stencil 做遮罩——门户外的像素不渲染。你需要:1)配置 stencil format(8-bit);2)用 addRenderContext 在 command buffer 上添加 render context;3)在 stencil attachment 上绘制 portal mask;4)用 render context 的 endEncoding 结束编码(而非 command encoder 的)。系统会在最后一步自动应用边缘淡出效果。
macOS Spatial Rendering(Mac 空间渲染)。 最大的新功能。Mac app 可以用 RemoteImmersiveSpace 把 immersive content 直接渲染到 Vision Pro。ARKit 和 WorldTrackingProvider 在 macOS 上也可用了(通过 RemoteDeviceIdentifier 传给 ARKitSession)。Mac app 支持键盘鼠标和 game controller 输入,也可以用 onSpatialEvent 处理 pinch 事件。渲染引擎如果是 C/C++ 实现的,可以用 cp 前缀的 C API 和 cDevice 属性桥接。
值得深挖的点
Tracking areas texture 是 hover effects 的基础设施。 它不只是视觉效果——还简化了空间事件处理。SpatialEvent 现在包含 trackingAreaIdentifier,直接告诉你事件发生在哪个对象上,不用自己做射线检测了。
Dynamic render quality 必须和 foveation 一起用。 如果 foveation 被禁用,你无法调整 render quality。这在低端设备或特定场景下可能是个限制。
Progressive immersion 的 stencil 只在 .layered layout 中工作。 这意味着它和 mixed immersion 风格不同——progressive 会用一个实际的门户窗口裁剪内容,mixed 则是把内容混合到真实环境中。
Mac spatial rendering 的延迟问题。 渲染发生在 Mac,显示在 Vision Pro,中间有网络传输。对于需要极低延迟的场景(如快速相机移动),要考虑 stream 延迟对体验的影响。
代码片段
配置 hover effects 并渲染 tracking areas:
// 配置 layer
var config = CompositorLayerConfiguration()
config.trackingAreasPixelFormat = .r8Uint // 8-bit,最多 255 对象
// 注册 tracking area 并设置 hover effect
let trackingArea = drawable.registerTrackingArea(
id: objectId,
renderValue: renderValue
)
if object.hasHoverEffect {
trackingArea.addHoverEffect(.automatic)
}
// Fragment shader
struct FragmentOut {
float4 color [[color(0)]];
uint trackingArea [[color(1)]];
};
fragment FragmentOut fragmentShader(VertexOut in [[stage_in]],
constant Uniforms &uniforms [[buffer(0)]]) {
FragmentOut out;
out.color = calculateColor(in);
out.trackingArea = uniforms.trackingAreaRenderValue;
return out;
}
Progressive immersion 的 stencil 遮罩:
// 配置 stencil
var config = CompositorLayerConfiguration()
config.stencilPixelFormat = .stencil8
// 渲染循环中
let renderContext = drawable.addRenderContext(commandBuffer: commandBuffer)
let stencilEncoder = commandBuffer.makeRenderCommandEncoder()!
stencilEncoder.setStencilReferenceValue(1)
// 绘制 portal mask...
stencilEncoder.endEncoding()
// 渲染场景(stencil 会裁剪门户外的像素)
// ...
renderContext.endEncoding() // 用 render context 结束,而非 command encoder
最佳实践
先 adopt queryDrawables 再用新功能。 所有新特性都依赖新的 drawables 数组 API。如果你还在用 queryDrawable,先迁移过来。
Hover effects 的 object ID 必须唯一且稳定。 不要每帧生成新 ID,要和对象生命周期绑定。255 个并发对象的上限对大多数 app 足够,但大型场景要注意管理。
Dynamic render quality 的 maxRenderQuality 设最低合理值。 设太高会浪费内存,因为即使你当前用 .6 的质量,maxRenderQuality 决定了 foveated texture 的最大尺寸。
Profile your app with Instruments + Metal debugger。 用最复杂的场景测试,确保帧率稳定。特别是在调整 render quality 或启用 hover effects 之后。
还有什么值得关注
- Xcode 的 visionOS Metal app template 更新了,直接支持选择 Metal 4 作为渲染后端。Metal 3 仍然完全支持。
- macOS spatial rendering 支持从已有的 AppKit 或 UIKit app 中创建 SwiftUI scene(通过新的 scene bridging API),不需要重写整个 app。
- Compositor Services 的 C API(
cp前缀)模式与 Core Foundation 类似,C/C++ 渲染引擎可以无缝迁移。 - 配套视频:“Set the scene with SwiftUI in visionOS”(Session 290)详细讲了 RemoteImmersiveSpace 的 SwiftUI 侧配置。