Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2026 Graphics & GamesSpatial Computing

WWDC26 · 14 min · Graphics & Games / Spatial Computing

Explore enhancements to visionOS object tracking

Find out how visionOS is advancing object tracking and spatial accessory input. Discover new ways to track moving and handheld objects, allowing you to bridge the physical and digital worlds. Learn about new supported classes of spatial accessories and what is needed to build your own custom accessories to enable unique interaction models in your apps.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 5 snippets

Enable high frame rate tracking swift · at 3:50 ↗
// Enable high frame rate tracking

// Create reference object configuration
var configuration = ReferenceObject.Configuration()
configuration.highFrameRateTrackingEnabled = true

// Load the reference object with ARKit API
let refObjURL = Bundle.main.url(forResource: "flashlight", withExtension: ".referenceobject")
let refObject = try? await ReferenceObject(from: refObjURL!, configuration: configuration)
Extended training mode via command-line bash · at 4:50 ↗
// Extended training mode on Mac using command-line interface

% xrun createml objecttracker --source flashlight.usdz --output flashlight.referenceobject --training-mode extended --all-angles
Object pose coordinate spaces swift · at 5:25 ↗
// Different object pose spaces

// Obtain anchor transform with display corrections

let renderingPose = myObjectAnchor.coordinateSpace(correction: .rendered)

// Obtain anchor transform in metric space

let metricPose = myObjectAnchor.coordinateSpace(correction: .none)
Implement object tracking in iOS swift · at 6:22 ↗
// Implement object tracking in iOS

import ARKit
import RealityKit

class ObjectTrackingARSessionDelegate: NSObject, ARSessionDelegate {
        let arView = ARView(frame: .zero)
        var entities: [UUID: AnchorEntity] = [:]

        func start() throws {
                let stationaryObject = try ARReferenceObject(archiveURL:
                        Bundle.main.url(forResource: "stationary", withExtension: "referenceobject")!)
                let movingObject = try ARReferenceObject(archiveURL:
                        Bundle.main.url(forResource: "moving", withExtension: "referenceobject")!)

                let configuration = ARWorldTrackingConfiguration()
                configuration.detectionObjects = [stationaryObject]   // Low frame rate
                configuration.trackingObjects = [movingObject]        // High frame rate

                arView.session.delegate = self
                arView.session.run(configuration)
        }

				func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
                for case let anchor as ARObjectAnchor in anchors {
                        let entity = AnchorEntity(anchor: anchor)
                        entities[anchor.identifier] = entity
                        arView.scene.addAnchor(entity)
                }
        }

        func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
                for case let anchor as ARObjectAnchor in anchors {
                        entities[anchor.identifier]?.isEnabled = anchor.isTracked
                }
        }

        func session(_ session: ARSession, didRemove anchors: [ARAnchor]) {
                for case let anchor as ARObjectAnchor in anchors {
                        if let entity = entities.removeValue(forKey: anchor.identifier) {
                                arView.scene.removeAnchor(entity)
                        }
                }
        }
}
Discover and connect a spatial accessory swift · at 12:26 ↗
import ARKit
import GameController

// Generic accessory discovery

if let device = GCSpatialAccessory.spatialAccessories.first {

        // Resolves the .referenceaccessory bundle automatically
        
        let accessory = try await Accessory(device: device)
        let provider = AccessoryTrackingProvider(accessories: [accessory])
        try await arkitSession.run([provider])
}

// Update tracked accessories without restarting the session                             

try await provider.updateAccessories([newAccessory])

Resources