Discover the Spatial Preview framework
visionOS & Spatial Computing 进阶 14m

探索 Spatial Preview 框架

Discover the Spatial Preview framework

2026年6月10日

在 Apple 官方观看视频

一句话判断

这场 Session 最值得关注的一件事是:Mac 开发者现在可以零 visionOS 代码,把 Mac App 里的 3D 模型和文档直接扔进 visionOS 的 Quick Look 里做双向实时编辑。

这场 Session 讲了什么

以前我们要让 Mac App 的内容在 Vision Pro 上立体展示,得硬着头皮写个 visionOS 伴侣 App,搞定网络传输、场景搭建、手势交互,头发掉一把。现在 Apple 直接甩出了空间预览(Spatial Preview)框架。你只需要在 Mac 端拿到设备端点(Endpoint),开个会话(Session),把文件 URL 或者通用场景描述(Universal Scene Description, USD)场景(Stage)塞进去,Vision Pro 上的 Quick Look 就会自动接管渲染和交互。

这对做 3D 建模、CAD、建筑设计或者全景视频工具的 Mac 开发者来说是绝对的福音。你不需要懂 RealityKit,只要懂你自家的 Mac 业务逻辑,加上几行 Spatial Preview 的 API 调用,你的 Mac App 瞬间就具备了“空间计算”卖点。影响最大的就是那些苦于没有资源开发 visionOS 原生 App 的中小型 Mac 工具软件团队,直接用这个框架就能把 Mac 生产力延伸到头显里。

值得深挖的点

零代码双向同步的魔法与代价

USDPreviewSession 最惊艳的地方在于它支持 Mac 和 visionOS 的双向实时编辑。你在 Mac 上改材质,Vision Pro 里秒更新;在 Vision Pro 里加个空间批注(AppleTextAnnotation),Mac 端的 USD 场景里也能立刻监听到变化。Apple 敢这么玩,是因为底层根本不是在做简单的文件传输,而是基于 USDKit 的 Stage 做了跨进程的内存级状态同步。

好在哪?省去了自己写 WebSocket 或 MultipeerConnectivity 同步状态的几万行代码,而且 Quick Look 自带了极其丝滑的手势操作和相机视角切换。坑在哪?这种强绑定的黑盒同步意味着你失去了对渲染管线的绝对控制权。如果你的 USD 场景里用了一些 Quick Look 不支持的自定义 Shader 或特殊 Prim,在 Mac 上看着正常,推到 Vision Pro 上可能直接丢失或者渲染报错。你只能乖乖遵守 Apple 定义的 USD 规范子集。

USD 自动优化的“隐形税”

Session 里提到一个很现实的细节:Vision Pro 的算力虽然强,但渲染 Mac 端那种几百万面的工业级 USD 场景还是会卡。所以 Spatial Preview 默认开启了自动优化(Optimization),偷偷帮你做网格减面(Mesh decimation)和纹理降采样。

这其实是个巨大的 Trade-off。对普通预览来说,自动优化保证了帧率,体验很顺滑。但如果你是做高精度工业评审的,减面会导致模型细节丢失,这绝对不能忍。Apple 提供了 .unmodified 参数让你关闭优化,但代价是如果场景太复杂,start 方法会直接抛出 assetUnshareable 错误。这意味着你必须在 Mac 端自己做一层 LOD(多细节层次)管理或者资产检查,不能无脑把原始资产扔给框架,否则用户点下“预览”按钮时只会看到一个冷冰冰的报错。

代码片段

1. 启动文档预览并监听会话状态

场景:把 Mac 上的全景视频或图片扔到 Vision Pro 里看,并处理用户关闭 Quick Look 的情况。

import SwiftUI
import SpatialPreview

// 监听已连接的空间端点
let deviceObserver = ConnectedSpatialEndpointObserver()
let previewSession = DocumentPreviewSession(name: "MyImmersiveVideo", contentType: .aivu)

func startPreview(contentURL: URL) async throws {
    // 获取当前 Mac Virtual Display 连接的 Vision Pro 端点
    let endpoint = try await deviceObserver.endpoint
    try await previewSession.start(endpoint: endpoint)
    
    // 把内容推送到 visionOS 的 Quick Look
    try await previewSession.updateContents(url: contentURL)
}

// 在 SwiftUI 中监听会话状态,防止用户在头显里关了场景导致 Mac 端状态不同步
.task(id: ObjectIdentifier(previewSession)) {
    for await state in previewSession.states {
        if state.isInvalidated {
            // 用户在 Vision Pro 里关闭了预览,清理 Mac 端状态
            print("会话已失效,清理 UI")
            break
        }
    }
}

坑:updateContents 会复用当前场景,如果你每次切换文件都重新 start,会导致 Vision Pro 上的场景闪烁重建,一定要用 updateContents 做画廊切换。

2. USD 实时同步与关闭自动优化

场景:加载高精度 3D 模型,关闭系统的自动减面优化,并处理模型过大无法分享的异常。

import SpatialPreview
import USDKit

func shareHighResStage(to endpoint: SpatialPreviewEndpoint) async throws {
    let stageURL = Bundle.main.url(forResource: "high_poly_car", withExtension: "usdz")!
    let stage = try USDStage.open(stageURL)
    
    let usdSession = USDPreviewSession(stage: stage)
    
    do {
        // 传入 .unmodified 关闭系统的自动减面和降采样
        try await usdSession.start(endpoint: endpoint, parameters: .unmodified)
    } catch USDPreviewSession.Error.assetUnshareable {
        // 模型面数或纹理太大,Vision Pro 扛不住,降级处理
        print("资产过于复杂,尝试加载低模版本")
        let lowResStage = try USDStage.open(Bundle.main.url(forResource: "low_poly_car", withExtension: "usdz")!)
        try await usdSession.updateStage(lowResStage)
    }
}

坑:关闭优化后,不要以为只要不报错就万事大吉,帧率依然可能掉到 30fps 以下。最好在 Mac 端提前计算一下 Stage 的包围盒和面数,给用户一个性能预警。

最佳实践

已有 Mac 3D/设计工具的项目,不要急着去重写一个 visionOS App。先花两天时间把 USDPreviewSession 接入进去,用 Quick Look 顶上。这能帮你用极低的成本验证“客户到底需不需要在空间里看模型”这个命题。

新项目如果重度依赖 3D 预览,建议直接拥抱 USDKit。以前大家可能习惯用 SceneKit 或自研引擎,但现在 Spatial Preview 只认 USD。把资产管线全面切到 USD,不仅能无缝接入 Spatial Preview,还能顺便蹭上 Apple 后续在 RealityKit 里的各种优化。

实战中极易踩坑的地方是设备发现。不要假设用户永远开着 Mac Virtual Display。一定要在 UI 里集成 SpatialPreviewDevicePicker,让用户能手动选择局域网内同一 iCloud 账号下的 Vision Pro,否则你的“预览”按钮在没连头显时就是个死按钮。

还有什么值得关注

  • Layout Variants 支持:USD 里的变体集(Variant Sets)现在可以直接在 Quick Look 里切换了,做室内设计 App 的可以直接用这个功能让用户在“现代风”和“原木风”家具布局间一键切换。
  • 空间批注(AppleTextAnnotation):visionOS 端加的 3D 批注会作为特殊的 Prim 写回 USD Stage,Mac 端可以通过 stage.addObserver 监听 ObjectsDidChange 直接拿到批注数据存进自己的数据库。
  • 进度监控USDPreviewSession 提供了 ProgressReporter,在传输几百 MB 的 USDZ 文件时,终于能在 Mac 端给用户展示一个真实的进度条,而不是瞎转圈的 Loading 动画了。
Spatial Preview USDKit visionOS Mac Virtual Display Quick Look