WWDC Quick Look 💓 By SwiftGGTeam
Break into the RealityKit debugger

Break into the RealityKit debugger

元の動画を見る

ハイライト

RealityKit Debugger は実行中アプリの 3D スナップショットを取得し、Xcode で Entity Hierarchy、3D ビューポート、Inspector の 3 カラムレイアウトを表示 — View Debugger が UIKit をデバッグするように spatial アプリをデバッグできます。


主要内容

3D アプリで最も困ることの一つ:コードでは確かに配置したのに、実行すると見えない、位置がおかしい、形が歪む。以前は print と経験で推測するしかありませんでした。RealityKit の Entity 階層と Transform 継承関係は複雑で、目視では問題箇所が分かりません。

Apple は Xcode に RealityKit Debugger を追加しました。View Debugger と同じ動作:デバッグエリアの “Capture Entity Hierarchy” ボタンをクリックして現在シーンの 3D スナップショットを取得し、Xcode で 3 カラムビューを開きます — 左に Entity Hierarchy ツリー、中央に 3D ビューポート、右に Inspector パネル。任意の Entity を選択すると 3 カラムが連動して階層位置、空間位置、全 Component プロパティを表示します。

このセッションは「植物園アプリをロボットナイトクラブに改造」する実プロジェクトで、4 種類の最も一般的な 3D バグの特定方法をデモ: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 の影響を受けない
  • 2 つの 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 で欠品管理、ロジックが明確
  • セッション推奨:シーンレイアウトは可能な限り Reality Composer Pro で、純コード配置より信頼性高い

4. カスタムデバッグ可視化

ロボットがナイトクラブにテレポート後、ダンスフロアに向かわず立ち止まります。開発者は #if DEBUG ブロックでデバッグ Entity を追加:各不可視アトラクターに半透明シリンダー可視化、カスタム AttractorDebugComponent で Inspector に状態とターゲット参照、DanceSystemDebugComponent で Swift Chart 円グラフ(UIImage プロパティとして保存)。

Debugger で全アトラクターが attracting 状態と一目で分かる — 通常 1 つのみのはず。アトラクターの attractor 参照リンクをクリックしてターゲットロボットにジャンプ、Newcomer Component が削除されていないことが判明、全アトラクターが同じロボットをロック。修正は 1 行のみ(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 を日常デバッグフローに組み込み、「表示異常」の第一反応は print ではなく Entity Hierarchy キャプチャ。なぜ価値があるか:3D シーンの階層関係と Transform 継承はコード読解ではほぼ推測不能、可視化ツールが問題階層を直接特定。始め方:visionOS シミュレータでアプリ実行、Xcode デバッグエリアの “Capture Entity Hierarchy” をクリック。

  • 何をするか:Entity に意味のある name プロパティを設定、例:"Disco Ball" でデフォルト空文字列ではなく。なぜ価値があるか:Debugger の Hierarchy ツリーは名前表示、名前空の Entity はトラブルシューティング時に識別不能。始め方:Entity 作成直後に entity.name = "説明的な名前" を設定。

  • 何をするか#if DEBUG ブロックでカスタム System にデバッグ可視化と Inspector Component を追加。なぜ価値があるか:ECS System が複雑になるほど実行時状態の追跡が困難、カスタム Component で Debugger がビジネスロジック状態を直接表示。始め方:セッションの DanceSystemDebugComponent パターンを参考 — カスタム Component でカウンターと Entity 参照を保持、UIImage プロパティでチャート表示も可能。

  • 何をするか:シーンレイアウトは Reality Composer Pro を優先、純コード 3D アセット配置を避ける。なぜ価値があるか:セッションの 9 ボトル 9 種類のエラーは全てコード内手動座標とプロパティ設定由来、ビジュアルエディタが根源からこの類の問題を削減。始め方:Reality Composer Pro でアセット配置・設定、エクスポート後 Entity.load(named:) でロード。


関連セッション

コメント

GitHub Issues · utterances