Highlight
RealityKit Debugger 截取运行中 App 的 3D 快照,在 Xcode 里呈现 Entity Hierarchy、3D 视口和 Inspector 三栏布局,让你像用 View Debugger 调 UIKit 一样调试 spatial 应用。
核心内容
做 3D 应用最头疼的事情之一:代码里明明放了东西,跑起来却看不到、位置不对、形状变形。以前只能靠 print 和经验猜,RealityKit 的 Entity 层级和 Transform 继承关系错综复杂,肉眼根本看不出来哪里出了问题。
Apple 在 Xcode 里新加了 RealityKit Debugger。它的工作方式跟 View Debugger 一样:点击调试区的”Capture Entity Hierarchy”按钮,截取当前场景的 3D 快照,然后在 Xcode 里打开三栏视图——左侧 Entity Hierarchy 树状结构、中间 3D 视口、右侧 Inspector 面板。选中任何一个 Entity,三栏联动显示它的层级位置、空间位置和所有 Component 属性。
这场 Session 用一个”把植物园 App 改成机器人夜店”的真实项目,演示了四类最常见的 3D bug 怎么用这个工具定位:Transform 继承导致的形状变形、Component 忘记写回导致的行为异常、渲染管线问题导致的内容缺失、以及用自定义 Component 给 Debugger 加调试信息的方法。每一类都是 3D 开发里的高频问题,有了可视化工具之后排查效率完全不同。
详细内容
1. Transform 继承导致的变形
迪斯科球的线条看起来被压扁了。在 Debugger 里选中 Outline Entity,Inspector 的预览视口显示模型本身没变形,Transform 组件的 scale 也是均匀的 1。问题不在自己,就在祖先节点。逐级往上查:Background 正常,但 Support Entity 的 Transform 在 Y 轴上有一个很大的 scale 值——Support 被拉长来塑造形状没错,但它把变形传给了所有后代。
修复方法:把 Support 和 Background 从父子关系改成兄弟关系(06:50)。
// 修复前:Background 是 Support 的子节点,继承了 Y 轴 scale
support.addChild(background)
// 修复后:Background 和 Support 是兄弟节点,都在 discoBall 下
discoBall.addChild(background)
关键点:
support.addChild(background)让 Background 继承了 Support 的 Y 轴 scale 变形- 改为
discoBall.addChild(background)后,Background 只继承 discoBall 的 Transform,不再受 Support 影响 - 两个 Entity 在场景里看起来仍然连在一起,但 Transform 不再相互干扰
2. Component 修改后忘记写回
传送系统应该不断生成机器人,但什么都没出现。在 Debugger 里检查 Teleporter Entity,Component 都在。再看 Teleportation Center 的 ControlCenterComponent,countdown 值一直等于初始值——说明 System 的 update 根本没生效。
回到代码发现问题:System 每次 update 都修改了 controlCenter.countdown,但修改后的 Component 没有写回 Entity(10:18)。
// TeleportationSystem.update 里遗漏的关键一步
// 5. Save updated component back to the entity
controlCenterEntity.components[ControlCenterComponent.self] = controlCenter
关键点:
- RealityKit 的 Component 是值类型(struct),从 Entity 取出来修改后必须写回才能生效
- 这跟 SwiftUI 里修改
@State的思维习惯不同,容易遗漏 - Debugger 捕获的是点击暂停那一刻的实时状态,countdown 值不变就说明 System 没有真正更新 Entity 上的数据
3. 渲染问题导致内容不可见
柜台上的 9 瓶机油只剩 1 瓶可见。用 Debugger 逐瓶排查,每一瓶的问题都不同:位置在柜台下方(被遮挡)、位置超出场景边界(被裁剪)、scale 过大导致摄像机在模型内部(三角面只渲染外表面)、Entity 未启用、残留了 AnchoringComponent 但场景里没有对应 ARKit anchor、ModelComponent 挂错了 Entity、Material 的 opacityThreshold 设为 1 同时 opacity 又小于 1(整瓶不可见)、Mesh 的法线方向反转(需要在 3D 工具里修复)、甚至完全忘记添加到场景。
修复方法是用一个创建循环替换掉所有复制粘贴的代码(18:15)。
private func stockBottles(placementRadius: Float) -> Entity {
let bottleRadius: Float = 0.003
let bottleHeight: Float = 0.022
let angleIncrement: Float = -12
let outOfStockBrands: Set = [3]
let bottleGroup = Entity()
bottleGroup.name = "Bottle Group"
bottleGroup.position = [0, 0.04, 0]
bottleGroup.orientation = .init(angle: 180 * (.pi / 180), axis: [0, 1, 0])
var bottleMaterial = PhysicallyBasedMaterial()
bottleMaterial.baseColor = .init(tint: .green)
bottleMaterial.blending = .transparent(opacity: .init(floatLiteral: 0.5))
for i in 0..<9 {
let angle = Angle2D(degrees: angleIncrement * Float(i))
let bottleMesh = MeshResource.generateCylinder(height: bottleHeight, radius: bottleRadius)
let bottle = ModelEntity(mesh: bottleMesh, materials: [bottleMaterial])
bottle.name = "BT\(i)"
bottle.position = pointOnCircumference(angle: angle, radius: placementRadius, y: bottleHeight / 2)
if outOfStockBrands.contains(i) {
bottle.components[OutOfStockComponent.self] = OutOfStockComponent()
}
bottleGroup.addChild(bottle)
}
return bottleGroup
}
关键点:
- 用循环创建代替手动复制粘贴,从根源消灭”复制时改错参数”的问题
pointOnCircumference统一计算位置,避免手动设错坐标outOfStockBrands用 Set 管理缺货项,逻辑清晰- Session 建议:场景布局尽量在 Reality Composer Pro 里做,比纯代码定位更可靠
4. 自定义调试可视化
机器人传送到夜店后站着不动,不走向舞池。开发者用 #if DEBUG 编译块添加了调试 Entity:给每个不可见的吸引子加了半透明圆柱体可视化,用自定义 AttractorDebugComponent 在 Inspector 里显示状态和目标引用,还用 DanceSystemDebugComponent 渲染了一张 Swift Chart 饼图(保存为 UIImage 属性)。
Debugger 里一眼看到所有吸引子都处于 attracting 状态——正常应该只有一个。点开吸引子的 attractor 引用链接跳到目标机器人,发现它的 Newcomer Component 没被移除,导致每个吸引子都锁定同一个机器人。修复只需一行(22:48)。
// 4. Untag them as a Newcomer
visitor.components[Newcomer.self] = nil
关键点:
- 自定义 Component 的属性会自动显示在 Inspector 里,包括 Entity 引用(变成可点击链接)
UIImage类型的属性可以在 Inspector 里显示图片,比如用 Swift Chart 渲染的状态饼图- 整个调试系统放在
#if DEBUG块里,Release 构建时会被编译器完全移除
核心启发
-
做什么:把 RealityKit Debugger 纳入日常调试流程,遇到”显示不正常”第一反应是截取 Entity Hierarchy 而不是加 print。为什么值得做:3D 场景的层级关系和 Transform 继承靠代码阅读几乎无法推断,可视化工具能直接定位问题层级。怎么开始:在 visionOS 模拟器运行你的 App,点击 Xcode 调试区的”Capture Entity Hierarchy”按钮。
-
做什么:给 Entity 取有意义的
name属性,比如"Disco Ball"而不是默认的空字符串。为什么值得做:Debugger 的 Hierarchy 树按名字显示,名字空的 Entity 排查时完全无法辨识。怎么开始:创建 Entity 后立即设置entity.name = "描述性名称"。 -
做什么:用
#if DEBUG编译块给自定义 System 加调试可视化和 Inspector Component。为什么值得做:你的 ECS System 越复杂,运行时的状态越难追踪,自定义 Component 能让 Debugger 直接展示你的业务逻辑状态。怎么开始:参考 Session 的DanceSystemDebugComponent模式——用自定义 Component 存计数器和 Entity 引用,UIImage属性还可以显示图表。 -
做什么:场景布局优先在 Reality Composer Pro 里完成,避免纯代码定位 3D 资产。为什么值得做:Session 里 9 个瓶子 9 种错误,全部来自代码里的手动坐标和属性设置,用可视化编辑器可以从源头减少这类问题。怎么开始:在 Reality Composer Pro 里摆放和配置资产,导出后用
Entity.load(named:)加载。
关联 Session
- Discover RealityKit APIs for iOS, macOS, and visionOS — RealityKit 跨平台 API 的最新更新和新增功能概览
- Compose interactive 3D content in Reality Composer Pro — 用 Reality Composer Pro 构建和预览交互式 3D 场景
- Build a spatial drawing app with RealityKit — 用 RealityKit API 在 visionOS 上构建空间绘画应用
- Create enhanced spatial computing experiences with ARKit — ARKit 最新 API 与空间计算体验开发
- Create custom environments for your immersive apps in visionOS — 为 visionOS 沉浸式应用创建自定义环境
评论
GitHub Issues · utterances