Highlight
Reality Composer Pro 3 支持通过 Xcode 编写插件,将自定义的 Component、System、动画 Action 和 Script Graph 节点暴露给编辑器,让美术和设计师在编辑器内直接调整参数、预览效果,无需反复编译部署 App。
核心内容
团队协作的痛点
做空间计算项目时,开发者和美术通常各自为战。工程师在 Xcode 里写代码控制 3D 场景逻辑,美术在 Reality Composer Pro 里摆放模型、调材质。双方的工作流是割裂的:美术想调一个参数看看效果,必须等工程师改完代码、编译、打包、部署到设备上才能验证。这个循环动辄几分钟,一天下来大量时间耗在等待上。
更大的问题是,工程师写的自定义 Component 和 System 对编辑器来说是黑盒。美术看不到这些组件的属性,也无法在编辑器里直接修改。所有调整都要通过工程师中转,沟通成本高,迭代速度慢。
Reality Composer Pro 3 的插件机制
Apple 今年的解决方案是插件化。工程师在 Xcode 里写一个动态库(Dynamic Library),把项目特有的 Component、System、动画 Action 注册到 Reality Composer Pro 3。编辑器加载这个插件后,这些自定义能力就会出现在编辑器的 UI 中,美术可以直接使用。
(02:07)整个工作流是这样的:Xcode 项目里有两个 Scheme,一个构建最终的游戏 App,另一个构建 RCPCustomComponents.framework 插件。Reality Composer Pro 3 项目与 Xcode 项目通过 simulation bar 关联,可以直接从编辑器启动 App。两个项目放在同一个 Git 仓库里,团队成员各自修改后提交合并。编辑器还自带了自定义的合并工具,处理 JSON 格式的内部数据时冲突更少。
(03:34)数据流向也很清晰:Xcode 构建 App 和插件,Reality Composer Pro 3 用插件加载自定义组件和系统,美术在编辑器里调整场景,最后导出为 Reality File 被 App 加载运行。
从 Script Graph 切换到代码的时机
(05:20)Reality Composer Pro 3 内置了 Script Graph 可视化脚本工具,不需要写代码就能实现很多逻辑。但 Script Graph 也有局限:图太大以后难以维护,而且无法调用 Script Graph 之外的其他 Apple API(比如 SwiftUI)。
演讲者举了一个例子:一口大锅(cauldron)里的水需要随材料加入而升降,还要有漩涡效果。这个逻辑如果完全用 Script Graph 做,图会很复杂。而且后续还要和食材漂浮系统联动,用代码实现更合理。
详细内容
自定义 Component 和 System
(06:07)第一步,定义一个 Component 来存储大锅的水位:
import RealityKit
public struct Cauldron: Component, Codable {
public var waterLevel: Float
enum CodingKeys: CodingKey {
case waterLevel
}
}
关键点:
Component协议让Cauldron可以被附加到 Entity 上Codable是必须的,这样 Reality Composer Pro 3 才能在编辑器中序列化这个组件,并保存到 Reality File 中CodingKeys用于控制哪些属性参与序列化;简单场景可以省略
(06:42)第二步,写 System 来响应水位变化:
import RealityKit
public struct CauldronSystem: System {
let query = EntityComponentQuery(Cauldron.self)
public init(scene: Scene) {}
public func update(context: SceneUpdateContext) {
for (entity, cauldron) in context.entities(matching: query) {
guard let water = entity.findEntity(named: "Cauldron_Water_mesh")
else { continue }
water.setPosition(SIMD3<Float>(0, 1, 0) * cauldron.waterLevel, relativeTo: entity)
}
}
}
关键点:
EntityComponentQuery(Cauldron.self)定义了系统关心的实体集合update(context:)每帧执行,遍历所有带有Cauldron组件的实体findEntity(named:)查找名为"Cauldron_Water_mesh"的子实体,即水面网格setPosition(_:relativeTo:)根据水位值调整水面高度
(07:00)第三步,创建插件让编辑器识别这些组件和系统:
import RealityComposerPro
final class RCPCustomComponentsPlugin: RealityComposerProPlugin {
public func setup(context: any RealityComposerProContext) {
context.registerComponent(Cauldron.self)
context.registerSystem(CauldronSystem.self)
}
}
@_cdecl("createRealityComposerProPlugin")
public func createRealityComposerProPlugin() -> UnsafeMutableRawPointer {
return RCPCustomComponentsPlugin().passRetained()
}
关键点:
RealityComposerProPlugin协议来自RealityComposerProSwift Package,在编辑器里通过 “Run With Xcode” 链接项目时会自动添加setup(context:)中注册组件和系统,编辑器加载插件后即可识别@_cdecl("createRealityComposerProPlugin")将函数导出为 C 符号,让插件加载器能找到入口passRetained()返回原始指针,因为插件加载器通过 DLL 接口调用
编译插件 Scheme 后,在 Reality Composer Pro 3 中打开项目,编辑器会提示是否信任插件。信任后,Cauldron 组件就会出现在 Custom Components 文件夹中。把它附加到大锅实体上,调整 waterLevel 属性,水面会实时响应。
(10:12)更棒的是,你可以在 Xcode 里给 System 的 update 方法打断点,attach 到编辑器进程上调试。代码在编辑器内部运行,调试体验和调试普通 App 一样。
与 Shader Graph 联动
(10:35)基础水位调好后,下一步是给水面加漩涡效果。技术美术已经在 Shader Graph 里做好了漩涡材质,有 rotationSpeed、vortexCoeff 等参数。我们需要从代码里驱动这些参数。
先扩展 Cauldron 组件,增加漩涡相关属性:
public struct Cauldron: Component, Codable {
public var waterLevel: Float
public var rotationSpeed: Float
public var minWaterLevel: Float
public var maxWaterLevel: Float
public var vortexCoeff: Float
}
(11:05)然后修改 CauldronSystem,把组件属性同步到 Shader Graph 材质参数:
public func update(context: SceneUpdateContext) {
for (entity, cauldron) in context.entities(matching: query) {
guard let water = entity.findEntity(named: "Cauldron_Water_mesh") else { continue }
water.setPosition(SIMD3<Float>(0, 1, 0) * cauldron.waterLevel, relativeTo: entity)
guard var model = water.components[ModelComponent.self] else { continue }
guard var mat = model.materials.first as? ShaderGraphMaterial else { continue }
let surface = computeSurface(cauldron: cauldron)
try? mat.setParameter(name: "Level Radius", value: .float(surface.levelRadius))
try? mat.setParameter(name: "Lowest Point",
value: .float(cauldron.waterLevel - surface.lowestPoint))
try? mat.setParameter(name: "Height Change", value: .float(surface.heightChange))
try? mat.setParameter(name: "Level Coeff", value: .float(surface.levelCoeff))
try? mat.setParameter(name: "Is Level", value: .bool(surface.isLevel))
model.materials[0] = mat
water.components.set(model)
}
}
关键点:
water.components[ModelComponent.self]取出实体的模型组件model.materials.first as? ShaderGraphMaterial获取 Shader Graph 材质setParameter(name:value:)设置材质参数,支持.float、.bool等类型- 修改后的材质需要重新赋值回
model.materials[0],再调用water.components.set(model)写回实体
每次重建插件后需要重启 Reality Composer Pro 3。重启时会显示组件变更的 diff 对话框,确认后新属性就会出现在编辑器中。调整 rotationSpeed,漩涡深度会实时变化。
自定义动画 Action
(13:25)Reality Composer Pro 3 的动画序列器(sequencer)支持自定义动画 Action。演讲者演示了一个让水位从 0.3 渐变到 0.5 的动画。
先定义 Action:
import RealityKit
public struct SetWaterLevelAction: EntityAction, Codable {
public let startWaterLevel: Float
public let endWaterLevel: Float
public var animatedValueType: (any AnimatableData.Type)? { Transform.self }
}
关键点:
EntityAction协议让 Action 可以被放入 sequencer timelineCodable保证 Action 能序列化到 Reality FileanimatedValueType返回Transform.self,这是EntityAction协议的要求,用于在动画执行器中访问目标实体
(14:05)再写执行逻辑:
extension SetWaterLevelAction {
static func subscribe() {
Task { @MainActor in
SetWaterLevelAction.subscribe(to: .updated) { event in
let normalizedTime = (event.playbackController.time - event.startTime) /
event.duration
let action = event.action
let currentLevel = action.startWaterLevel +
Float(normalizedTime) * (action.endWaterLevel - action.startWaterLevel)
guard let entity = event.targetEntity else { return }
guard var cauldron = entity.components[Cauldron.self] else { return }
cauldron.waterLevel = currentLevel
entity.components.set(cauldron)
}
}
}
}
关键点:
subscribe(to: .updated)监听动画更新事件normalizedTime计算当前动画进度(0 到 1)- 用线性插值计算当前水位:
start + progress * (end - start) - 从
event.targetEntity获取目标实体,更新其Cauldron组件
(14:56)最后在插件中注册 Action 并调用 subscribe():
final class RCPCustomComponentsPlugin: RealityComposerProPlugin {
public func setup(context: any RealityComposerProContext) {
context.registerComponent(Cauldron.self)
context.registerSystem(CauldronSystem.self)
context.registerAction(SetWaterLevelAction.self)
SetWaterLevelAction.subscribe()
}
}
注册后,在编辑器中创建序列(Sequence),添加动画轨道,把 SetWaterLevelAction 拖到 timeline 上,设置起始和结束水位,播放即可看到水位渐变动画。
自定义 Script Graph 节点
(17:32)Script Graph 是 Reality Composer Pro 3 的可视化脚本系统,让设计师不写代码就能做交互。通过插件,可以把自定义组件暴露为 Script Graph 节点。
最简单的方式是用 @Scriptable 宏:
import RealityKit
import RealityKitScripting
import RealityKitScriptingMacros
@Scriptable
public struct Cauldron: Component, Codable {
public var waterLevel: Float
public var rotationSpeed: Float
public var minWaterLevel: Float
public var maxWaterLevel: Float
public var vortexCoeff: Float
}
关键点:
@Scriptable宏会自动生成SchemaProvider.schema,描述组件的属性结构- 需要导入
RealityKitScripting和RealityKitScriptingMacros - 这两个模块和
RealityComposerProSwift Package 一样,在通过编辑器创建 Xcode 项目时自动配置
(18:08)然后在插件中注册脚本模块:
public func setup(context: any RealityComposerProContext) {
context.registerComponent(Cauldron.self)
context.registerSystem(CauldronSystem.self)
context.registerAction(SetWaterLevelAction.self)
SetWaterLevelAction.subscribe()
Task { @MainActor in
let config = RKS.Configuration(id: "ChaparralVillage")
.onInitialize { _ in
[
Module("ChaparralVillage") {
Cauldron.SchemaProvider.schema
}
]
}
try! RKS.addConfiguration(config)
}
}
关键点:
- 脚本模块注册必须在主线程执行,所以包在
Task { @MainActor in ... }中 RKS.Configuration(id:)创建项目专属的配置onInitialize闭包返回模块列表,每个模块包含组件的 schemaRKS.addConfiguration(config)将配置添加到 RealityKitScripting 系统
注册后,给大锅实体添加 Scripting 组件,打开 Script Graph 编辑器。添加 Update 节点、If 节点检测按键,把 If 的 true 分支连到 Set Water Level 节点,设置按键 “a” 对应水位 0.25,按键 “z” 对应水位 0.5。打开 simulation view 按 “a” 和 “z”,水位会实时升降。
核心启发
1. 做一个可实时调整的粒子系统编辑器
用自定义 Component 存储粒子参数(发射速率、生命周期、颜色渐变),用 System 驱动粒子行为。美术在 Reality Composer Pro 3 里调参数,实时看到粒子效果变化。入口 API:Component、System、RealityComposerProPlugin。
2. 把物理交互逻辑做成可视化节点
用 @Scriptable 宏把自定义物理组件暴露给 Script Graph。设计师可以拖拽节点来配置碰撞响应、重力场强度,不需要写代码。入口 API:@Scriptable、RKS.Configuration。
3. 做一套角色动画状态机
定义多个 EntityAction(Idle、Walk、Jump),每个 Action 控制骨骼动画和位移。在 sequencer 里编排状态切换的时间线,设计师可以直接在编辑器里调整过渡时长和混合权重。入口 API:EntityAction、subscribe(to: .updated)。
4. 材质参数实时预览工具
把 PBR 材质的各个参数(roughness、metallic、emissive)做成自定义 Component,System 每帧同步到 Shader Graph 材质。美术调整滑块就能看到不同材质效果,比反复导出测试快得多。入口 API:ShaderGraphMaterial.setParameter(name:value:)。
5. 多人协作的空间场景版本控制
利用 Reality Composer Pro 3 的自定义合并工具和 Git 集成,把场景数据(JSON)和代码放在同一个仓库。工程师改插件、美术改场景,各自提交后自动合并,减少冲突。入口:编辑器内置的 merge tool + simulation bar 关联 Xcode 项目。
关联 Session
- Iterate your spatial scenes faster with Reality Composer Pro 3 — Reality Composer Pro 3 的新功能和美术工作流
- Design no-code games with Reality Composer Pro 3 — 用 Script Graph 不写代码做游戏
- Explore advances in RealityKit — RealityKit 最新 API 和能力
- Supercharge your spatial workflows with Reality Composer Pro 3 — 提升编辑器生产力的技巧
评论
GitHub Issues · utterances