在 Xcode 中使用 Reality Composer Pro 内容
Work with Reality Composer Pro content in Xcode
2023年6月5日
一句话判断
Reality Composer Pro 项目本质上是 Swift Package——你可以在里面创建自定义 Component、用 Shader Graph 制作材质、通过 RealityView 加载场景、用 Attachments API 在 3D 空间中放置 SwiftUI 视图,整个 ECS 架构与代码无缝衔接。
这场 Session 讲了什么
RealityKit 和 Reality Composer Pro 团队的 Amanda 介绍了如何在 Xcode 中加载和操作 Reality Composer Pro 创建的内容。
以优胜美地地形图为案例,Session 展示了完整的开发流程:在 Reality Composer Pro 中组装场景、创建自定义组件、在 Xcode 中加载场景并添加交互。
ECS 架构:Entity-Component-System 是 RealityKit 的核心架构。Entity 是场景中的任何物体(可见或不可见),Component 存储数据(可动态添加/移除),System 提供每帧执行的行为逻辑。这和面向对象的继承模型不同——Entity 的”性质”由其拥有的 Component 组合决定。
从 Reality Composer Pro 加载内容:使用 Entity 的异步初始化器,指定场景名称和 bundle。Reality Composer Pro 项目编译后产生 realityKitContentBundle,Xcode 自动生成这个常量。
自定义 Component:在 Reality Composer Pro 中创建自定义 Component,它会在 Xcode 中生成对应的 Swift 文件。你可以在其中添加属性(如兴趣点的名称和描述),然后在 Reality Composer Pro 的 Inspector 中填写这些属性的值。
RealityView:SwiftUI 的新视图类型,是连接 SwiftUI 和 RealityKit 的桥梁。在 make 闭包中加载实体,在 update 闭包中响应状态变化。
Attachments API:允许在 3D 场景中定位 SwiftUI 视图。比如在地图上方的兴趣点位置放置 2D 信息按钮。
Shader Graph 集成:在 Reality Composer Pro 中创建的 MaterialX 着色器可以在代码中通过 Component 动态控制参数。
值得深挖的点
Reality Composer Pro 项目是 Swift Package:这意味着你可以在同一个项目中同时编辑 3D 场景和 Swift 代码。自定义 Component 生成的 Swift 文件就在 Package 中,可以直接编辑。
场景加载的命名机制:Reality Composer Pro 中的每个标签页(tab)代表一个根实体,可以在运行时通过字符串名称加载。一个项目可以有多个场景——既可以作为完整场景加载,也可以作为可复用的组件(assemblage)加载。
Attachments 的 SwiftUI-3D 桥接:Attachments API 让你可以在 3D 空间的特定位置放置 SwiftUI 视图。位置由 Reality Composer Pro 中的实体位置决定,视图内容由 SwiftUI 代码决定。这是 2D UI 和 3D 场景交互的关键机制。
自定义 Component 的双向编辑:在 Reality Composer Pro 中创建 Component 的属性结构,在 Xcode 中编写属性逻辑,再回到 Reality Composer Pro 中填写属性值。这个往返工作流非常流畅。
代码片段
// 从 Reality Composer Pro 加载场景
RealityView { content in
let entity = try await Entity(
named: "DioramaAssembled",
in: realityKitContentBundle
)
content.add(entity)
}
// 自定义 Component - 在 Reality Composer Pro 中创建
// 自动生成 Swift 文件 PointOfInterestComponent.swift
struct PointOfInterestComponent: Component {
var name: String = ""
var description: String = ""
// 可以添加计算属性和方法
var displayName: String {
name.replacingOccurrences(of: "_", with: " ")
}
}
// RealityView + Attachments - 在 3D 空间中放置 SwiftUI 视图
RealityView { content in
let scene = try await Entity(named: "DioramaAssembled",
in: realityKitContentBundle)
content.add(scene)
} attachments: {
// 为每个兴趣点创建 SwiftUI 按钮
ForEach(pointsOfInterest) { poi in
Attachment(id: poi.name) {
Button(action: { showDetail(poi) }) {
VStack {
Image(systemName: "info.circle")
Text(poi.displayName)
.font(.caption)
}
}
}
}
}
// 查找特定实体并读取自定义 Component
let entity = scene.findEntity(named: "Ribbon_Beach")
if let poiComponent = entity?.components[PointOfInterestComponent.self] {
print("兴趣点: \(poiComponent.name)")
print("描述: \(poiComponent.description)")
}
// 动态修改 Component
entity?.components.set(PointOfInterestComponent(
name: "Ribbon Beach",
description: "Catalina Island 的美丽海滩"
))
// 控制 Shader Graph 材质参数
// 在 Reality Composer Pro 中创建的材质参数
// 可以通过 ShaderGraphMaterial 在代码中修改
if let component = entity.components[ShaderGraphMaterial.self] {
var material = component
try material.setParameter(name: "MorphAmount", value: Float(0.5))
entity.components.set(material)
}
最佳实践
- USD 资产放入 .rkassets 目录:Xcode 会将 .rkassets 编译为运行时更快加载的格式。不要直接使用裸 USD 文件。
- 用命名实体定位关键元素:在 Reality Composer Pro 中为需要在代码中访问的实体命名,运行时用
findEntity(named:)查找。 - 自定义 Component 在 Reality Composer Pro 中创建:而不是纯代码创建。这样视觉编辑和代码编辑可以并行工作。
- Attachments 用于 2D-3D 混合 UI:在 3D 场景上方浮动的信息卡片、标签和按钮用 Attachments API,不要尝试用纯 RealityKit 实现。
- 用 System 处理每帧逻辑:需要持续更新的行为(如动画、物理模拟)放在 ECS 的 System 中,而不是 SwiftUI 的视图更新中。
还有什么值得关注
- RealityView 是 SwiftUI 和 RealityKit 之间的官方桥梁,使用它而不是 UIViewRepresentable 桥接。
- .rkassets 是编译优化后的格式,直接使用 USD 文件会明显更慢。
- Session 展示了一个地形图在优胜美地和 Catalina Island 之间变形的效果,这个 morph 动画通过 Shader Graph 的参数驱动。
- Reality Composer Pro 的 Component 编辑器和 Xcode 的 Swift 代码编辑器之间的双向同步是整个工作流的核心。