WWDC Quick Look 💓 By SwiftGGTeam
Create enhanced spatial computing experiences with ARKit

Create enhanced spatial computing experiences with ARKit

元の動画を見る

ハイライト

ARKit は visionOS 2.0 で Room Tracking を追加し、従来は幾何頂点のみだった mesh データを部屋境界の意味論を持つ RoomAnchor にアップグレード。app が部屋ごとに仮想コンテンツを切り替え可能に。


主要内容

visionOS app を作る開発者は皆同じ問題に直面します:ARKit は mesh 頂点と平面アンカーを提供しますが、コードは「ユーザーが今どの部屋にいるか」を判断できません。座標と幾何で推測するしかなく、推測が外れると仮想コンテンツが間違った場所に配置されます。Super Fruit Ninja がフルーツの残骸を床に散らせるのは scene understanding のおかげですが、昨年の API は平面と mesh しか認識できず、「部屋」レベルの意味論は不可能でした。

今年 ARKit は Room Tracking を追加し、ユーザーが現在いる部屋の境界、壁と床の幾何を直接伝え、リビングから寝室へ移動するとデータソースを自動切り替えします。同時に Object Tracking が追加され、USDZ モデルで実物体を登録すると ARKit が位置と向きを継続追跡。教育や産業など、実物に仮想コンテンツを重ねるシナリオに適しています。Plane Detection に Slanted アライメントも追加され、斜面を検出可能に。さらに World Tracking は暗所で自動的に向きのみの追跡に降级し、Hand Tracking は display-rate 出力と手の予測をサポートしてインタラクション遅延を低減。


詳細

Room Tracking

RoomTrackingProvider は今年追加された DataProvider で、world sensing 認可が必要です。現在の部屋の RoomAnchor と非同期 anchor 更新シーケンスを提供します(03:35)。

// RoomTrackingProvider

@available(visionOS, introduced: 2.0)
public final class RoomTrackingProvider: DataProvider, Sendable {

    /// The room which a person is currently in, if any.
    public var currentRoomAnchor: RoomAnchor? { get }

    /// An async sequence of all anchor updates.
    public var anchorUpdates: AnchorUpdateSequence<RoomAnchor> { get }

    ...
}

キーポイント:

  • currentRoomAnchor は現在の部屋のアンカーを直接返す。nil は ARKit が閉鎖空間を認識していない
  • anchorUpdates は非同期シーケンスで、部屋切り替えイベントの監視に適する
  • RoomTrackingProvider は現在所在部屋の anchor データのみ更新し、すべての履歴部屋を同時更新しない

各 RoomAnchor には部屋の幾何情報が含まれます(04:20):

@available(visionOS, introduced: 2.0)
public struct RoomAnchor: Anchor, Sendable, Equatable {
    /// True if this is the room which a person is currently in.
    public var isCurrentRoom: Bool { get }

    /// Get the geometry of the mesh in the anchor's coordinate system.
    public var geometry: MeshAnchor.Geometry { get }
    /// Get disjoint mesh geometries of a given classification.
    public func geometries(of classification: MeshAnchor.MeshClassification) ->
        [MeshAnchor.Geometry]

    /// True if this room contains the given point.
    public func contains(_ point: SIMD3<Float>) -> Bool

    /// Get the IDs of the plane anchors associated with this room.
    public var planeAnchorIDs: [UUID] { get }
    /// Get the IDs of the mesh anchors associated with this room.
    public var meshAnchorIDs: [UUID] { get }
}

キーポイント:

  • isCurrentRoom でこのアンカーがユーザーの現在部屋か判断し、部屋ごとの仮想コンテンツ切り替えに使用
  • geometry は通常の mesh anchor より部屋境界に沿った mesh を返す
  • geometries(of:) は分類(壁/床)ごとに分離した幾何を返し、オクルージョンや壁全体の仮想ポータルに有用
  • contains(_:) で 3D 点が部屋内か判断。world tracking と組み合わせ「特定の部屋に入ったときだけトリガー」を実現
  • planeAnchorIDsmeshAnchorIDs で現在部屋に属するアンカーをフィルタし、部屋外データへの高コスト計算を回避

Object Tracking

Object Tracking はまず CreateML で ReferenceObject を生成し、ランタイムでロードして追跡を開始する必要があります(08:06)。

// Object tracking

Task {
    do {
        let url = URL(fileURLWithPath: "/path/to/globe.referenceobject")
        let referenceObject = try await ReferenceObject(from: url)
        let objectTracking = ObjectTrackingProvider(referenceObjects: [referenceObject])
    } catch {
        // Handle reference object loading error.
    }
    ...
}

キーポイント:

  • ReferenceObject はファイル URL または Bundle からロード
  • 1 つの ObjectTrackingProvider で複数 ReferenceObject を同時追跡可能
  • ロード失敗は例外をスローし、catch で処理が必要

session を開始して状態を監視(08:27):

let session = ARKitSession()

Task {
    do {
        try await session.run([objectTracking])
    } catch {
        // Handle session run error.
    }

    for await event in session.events {
        switch event {
        case .dataProviderStateChanged(_, newState: let newState, _):
            if newState == .running {
                // Ready to start processing anchor updates.
            }
        ...
        }
    }
}

キーポイント:

  • session.run() は async で await が必要
  • DataProvider が .running 状態になってから anchor 更新を処理可能
  • session.events で状態変化を非同期監視

追跡結果は ObjectAnchor 形式で返されます(08:43):

// ObjectAnchor

@available(visionOS, introduced: 2.0)
public struct ObjectAnchor: TrackableAnchor, Sendable, Equatable {

    /// An axis-aligned bounding box.
    public struct AxisAlignedBoundingBox: Sendable, Equatable {
        ...
    }

    /// The bounding box of this anchor.
    public var boundingBox: AxisAlignedBoundingBox { get }

    /// The reference object which this anchor corresponds to.
    public var referenceObject: ReferenceObject { get }
}

キーポイント:

  • boundingBox は検出物体の軸平行境界ボックスを提供。center、extent、最小/最大座標を取得可能
  • referenceObject は一致した ReferenceObject を指し、元の USDZ ファイルパスを取得可能
  • Object Tracking は静止配置の物体のみ追跡。運動中の物体は不可

World Tracking の照度降级

暗所では ARKit が完全追跡から向きのみの追跡に自動降级。SwiftUI に worldTrackingLimitations 環境値が追加され app に通知(11:03):

struct WellPreparedView: View {
    @Environment(\.worldTrackingLimitations) var worldTrackingLimitations

    var body: some View {
        ...

        .onChange(of: worldTrackingLimitations) {
            if worldTrackingLimitations.contains(.translation) {
                // Rearrange content when anchored positions are unavailable.
            }
        }
    }
}

キーポイント:

  • .translation が limitations に現れると位置追跡は利用不可で向き追跡のみ
  • このコールバックで配置済み仮想コンテンツを再配置するか、より明るい環境への移動を促せる
  • システムレベルでは既に向き追跡に自動降级——完全に追跡が失われることはない

Hand Tracking 予測

HandTrackingProvider は display rate でデータを出力。Compositor Services レンダリングシーンで手の位置を事前予測する新 API も追加(12:51):

// Hands prediction

func submitFrame(_ frame: LayerRenderer.Frame) {
    ...

    guard let drawable = frame.queryDrawable() else { return }

    // Get the trackable anchor time to target.
    let trackableAnchorTime = drawable.frameTiming.trackableAnchorTime

    // Convert the timestamp into units of seconds.
    let anchorPredictionTime = LayerRenderer.Clock.Instant.epoch.duration(to:
        trackableAnchorTime).timeInterval

    // Predict hand anchors for the time that provides best content registration.
    let (leftHand, rightHand) = handTracking.handAnchors(at: anchorPredictionTime)

    ...
}

キーポイント:

  • trackableAnchorTime は visionOS 2.0 の新タイムスタンプで、最適なコンテンツ整合時刻を表す
  • 秒に変換して handAnchors(at:) に渡すと ARKit が前方予測
  • 予測結果は遅延が低いが精度はやや犠牲——手に密着したシーン向け
  • 精度重視で遅延に鈍感(ジェスチャー検出、描画)なら display-rate の非同期更新が適切

重要ポイント

  1. 部屋ベースの体験切り替え:RoomTrackingProvider の isCurrentRoomcontains(_:) で各部屋に異なる仮想コンテンツをカスタマイズ。価値がある理由:ユーザーは「部屋が変わると見えるものも変わる」体験を直感的に期待。座標による手動分区より信頼性が高い。始め方:Full Space で RoomTrackingProvider を有効化し、anchorUpdates を監視、切り替え時にシーンコンテンツを交換。

  2. 実物体への仮想情報オーバーレイ:Object Tracking で産業機器、教材、ボードゲーム部品に 3D ラベルやアニメーションを重ねる。価値がある理由:教育、修理、博物館シナリオは「実物を見ながら解説」のインタラクションが自然。visionOS 上でこの類の app はまだ少ない。始め方:CreateML で ReferenceObject を訓練し ObjectTrackingProvider で実行。ObjectAnchor の boundingBox でオーバーレイ位置を決定。

  3. 暗所での適切な降级worldTrackingLimitations を監視し、位置追跡喪失時に仮想コンテンツをアンカーモードから視点追従モードへ自動切替。価値がある理由:ユーザーは常に明るい環境にいるわけではない。降级なしではコンテンツが漂移または消失。始め方:SwiftUI ビューで .onChange(of: worldTrackingLimitations) により .translation 制限を検出し、コンテンツ再配置をトリガー。

  4. 低遅延の手インタラクション:手に密着したシーン(仮想物体の掴みなど)ではデフォルトの非同期更新ではなく手予測 API を使用。価値がある理由:非同期 HandAnchor には固有の遅延があり、手が速いと仮想物体が「手についてこない」。予測でギャップを縮小。始め方:Compositor Services レンダーループで drawable.frameTiming.trackableAnchorTime から目標時刻を取得し、handAnchors(at:) で予測結果を取得。


関連セッション

コメント

GitHub Issues · utterances