Highlight
visionOS 的空间计算平台基于 SwiftUI、RealityKit 和 ARKit 三个熟悉的框架,通过 Window、Volume 和 Full Space 三种容器,让开发者可以用同一套代码构建从 2D 窗口到完全沉浸式体验的应用。
核心内容
三种空间容器
visionOS 的核心设计围绕三种容器展开(01:27):
Window(窗口)
Window 是 SwiftUI 的 Scene,可以调整大小、重新布局,和 macOS 窗口的行为类似。但它支持混合 2D 和 3D 内容,你可以在一个窗口里同时放按钮和一个 3D 模型。
Volume(体积)
Volume 是在 Shared Space 中展示 3D 内容的固定边界容器(02:07)。它适合展示棋盘、地球仪这类可以从不同角度查看的 3D 内容。Volume 也是 SwiftUI Scene,用 RealityKit 渲染 3D。
Full Space(全空间)
Full Space 让你的应用独占整个视野,其他应用被隐藏(02:47)。在 Full Space 中可以使用 ARKit 的 API,比如骨骼手部追踪(Skeletal Hand Tracking)。Full Space 有三种沉浸风格:
- Mixed:在真实环境(passthrough)上叠加虚拟内容
- Full:完全隐藏真实环境,只显示虚拟内容
- Progressive:初始显示真实环境,用户可以通过数码表冠调节沉浸程度
自然交互方式
visionOS 的交互基于眼睛和双手(04:30):
- 看着按钮,手指轻触(tap)即可选中
- 可以直接伸手触摸 3D 空间中的按钮
- 系统支持 tap、long press、drag、rotate、zoom 等手势
- SwiftUI 的手势 API 和 RealityKit Entity 无缝集成
ARKit 的骨骼手部追踪让更复杂的手势成为可能,比如把用户的手变成虚拟球杆来打保龄球(05:36)。
隐私优先的架构
visionOS 的隐私设计很严格(07:47)。应用不能直接访问传感器数据,系统会把原始数据转换成事件和视觉提示再交给应用。比如:
- 系统知道用户眼睛和手的 3D 位置,但只传递 touch 事件给应用
- 当用户注视某个视图时,系统会渲染 hover 效果,但不会告诉应用用户在看哪里
- 需要访问场景理解(检测墙壁、家具)或骨骼手部追踪时,系统会先征求用户许可
详细内容
开发工具链
Xcode 为 visionOS 提供了完整的开发工具(09:05):
Xcode Preview
Preview Canvas 支持 3D 预览,可以直接在代码编辑时看到 RealityKit 场景的渲染结果,包括动画效果(09:34)。Object Mode 可以快速预览 3D 布局,检查内容是否在视图边界内。
Simulator
Simulator 支持用键盘、鼠标或游戏手柄在场景中移动和观察。自带三种模拟场景,每种都有白天和夜晚光照(11:03)。
RealityKit Trace
Instruments 15 新增了 RealityKit Trace 模板,可以分析 GPU、CPU 和系统功耗影响,追踪帧瓶颈,查看提交的三角形总数和模拟的 RealityKit Entity 数量(12:24)。
Reality Composer Pro
新的 3D 内容编辑工具,支持:
- 粒子系统(云、雨、火花等效果)
- 空间音频预览
- 基于物理的材质(PBR)
- MaterialX 自定义材质节点图(14:32)
创建 Window
Window 通过 WindowGroup 创建,可以混合 2D 和 3D 内容:
import SwiftUI
import RealityKit
@main
struct HelloWorldApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, World!")
// 在窗口中嵌入 3D 内容
Model3D(named: "Satellite") { model in
model
.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
ProgressView()
}
}
}
}
关键点:
Model3D类似Image,加载并显示由 RealityKit 渲染的 3D 模型- 窗口中的 3D 内容会沿 z 轴突出,增加深度感
- 可以用
DragGesture直接拖拽 3D 实体
创建 Volume
Volume 通过设置 windowStyle 为 .volumetric 创建:
@main
struct EarthApp: App {
var body: some Scene {
WindowGroup(id: "earth") {
EarthView()
}
.windowStyle(.volumetric)
.defaultSize(width: 0.6, height: 0.6, depth: 0.6, in: .meters)
}
}
关键点:
.windowStyle(.volumetric)把 WindowGroup 变成 VolumedefaultSize指定体积的宽高深,单位可以是.points或.meters- Volume 内容必须保持在边界内
- 适合 Shared Space,可以和其他窗口共存
RealityView 和 Attachments
RealityView 是在 SwiftUI 中管理 RealityKit 实体的核心视图:
import SwiftUI
import RealityKit
struct GlobeView: View {
var body: some View {
RealityView { content, attachments in
// make closure: 创建实体并添加到根实体
if let earth = try? await Entity(named: "Earth") {
content.add(earth)
}
// 把 attachment 添加到场景中
if let pin = attachments.entity(for: "pin") {
pin.position = [0, 0.5, 0]
content.add(pin)
}
} update: { content, attachments in
// update closure: 状态变化时调用
} attachments: {
// attachments closure: 定义 SwiftUI 视图
Attachment(id: "pin") {
Image(systemName: "mappin")
.font(.largeTitle)
.foregroundColor(.red)
}
}
}
}
关键点:
makeclosure 在视图创建时执行一次,用于初始化实体updateclosure 在 SwiftUI 状态变化时调用attachments把 SwiftUI 视图转换为可以放在 3D 场景中的实体- 每个 attachment 需要一个唯一的
id
创建 Full Space
Full Space 通过 ImmersiveSpace Scene 类型创建:
@main
struct SpaceApp: App {
@State private var immersiveStyle: ImmersionStyle = .full
var body: some Scene {
WindowGroup {
ContentView()
}
ImmersiveSpace(id: "outerSpace") {
OuterSpaceView()
}
.immersionStyle(selection: $immersiveStyle, in: .full, .mixed, .progressive)
}
}
struct ContentView: View {
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
var body: some View {
Button("Enter Space") {
Task {
await openImmersiveSpace(id: "outerSpace")
}
}
}
}
关键点:
ImmersiveSpace定义一个可进入的全空间场景.immersionStyle设置沉浸风格,默认是.mixedopenImmersiveSpace环境值用于打开空间dismissImmersiveSpace环境值用于关闭空间- 建议给用户选择是否进入沉浸式体验的按钮
手势与 3D 实体交互
SwiftUI 的手势可以直接 targeting RealityKit 实体:
Model3D(named: "Satellite") { model in
model
.resizable()
.aspectRatio(contentMode: .fit)
}
.placeholder {
ProgressView()
}
.gesture(
DragGesture()
.targetedToEntity(named: "Satellite")
.onChanged { value in
// 根据拖拽值移动实体
value.entity.position = value.convert(value.location3D, from: .local, to: .parent)
}
)
关键点:
.targetedToEntity(named:)把手势绑定到特定实体value.location3D获取 3D 空间中的拖拽位置convert(_:from:to:)在坐标空间之间转换位置
从现有 App 迁移
visionOS 支持三种迁移路径(15:40):
- 兼容模式:iPad/iPhone App 无需修改即可运行,系统会自动处理窗口缩放和旋转
- 重新编译:在 Xcode 中添加 visionOS 目标,重新编译后获得原生间距、尺寸和重排
- 全新设计:使用 visionOS App 模板,从 Window 或 Volume 开始,充分利用空间计算能力
核心启发
用 Model3D 给现有 App 增加深度感
- 做什么:在现有 SwiftUI App 的某个视图里加一个
Model3D,展示一个 3D 产品模型 - 为什么值得做:不需要写任何 RealityKit 代码,
Model3D就像用Image一样简单,但能给界面增加空间深度 - 怎么开始:把 USDZ 模型拖到 Xcode 项目中,用
Model3D(named: "模型名")加载
做一个可旋转查看的 3D 商品展示
- 做什么:用 Volume 展示一个 3D 商品模型,用户可以从各个角度查看
- 为什么值得做:Volume 天生适合展示 3D 内容,用户可以用手势旋转、缩放,比 2D 图片直观得多
- 怎么开始:创建
WindowGroup,设置.windowStyle(.volumetric),在里面放RealityView加载商品模型
设计一个渐进式沉浸的冥想 App
- 做什么:App 启动时在 Shared Space 显示控制面板,点击开始后进入 Full Space,用 Progressive 沉浸风格让用户自己调节沉浸程度
- 为什么值得做:Progressive 沉浸让用户有控制权,从轻度沉浸逐步过渡到完全沉浸,减少不适感
- 怎么开始:用
ImmersiveSpace创建场景,设置.immersionStyle(selection: $style, in: .progressive)
用 RealityView Attachments 做 3D 地图标记
- 做什么:在 3D 地球仪或地图上,用 SwiftUI 视图作为标记点(pin)
- 为什么值得做:Attachments 让你可以用熟悉的 SwiftUI 代码创建 3D 场景中的 UI 元素,不需要学习新的 UI 框架
- 怎么开始:在
RealityView的attachmentsclosure 里定义标记视图,在makeclosure 里用attachments.entity(for: "id")获取并放置
关联 Session
- Build spatial experiences with RealityKit — 用 RealityKit 构建空间体验
- Meet ARKit for spatial computing — ARKit 在空间计算中的应用
- Develop your first immersive app — 开发第一个沉浸式应用
评论
GitHub Issues · utterances