How to create a Spatial Tracking Session

Configure and run a Spatial Tracking Session to use ARKit features in RealityKit.

According to the documentation, SpatialTrackingSession aims to simplify the use of ARKit features in RealityKit.

We will use both hand and plane detection in this example. First, we need to add two values to our application info.plist file.

NSHandsTrackingUsageDescription
NSWorldSensingUsageDescription

Let’s create a session for our view

@State var trackingSession: SpatialTrackingSession = SpatialTrackingSession()

Then create a function to configure and run it.

func runTrackingSession() async {
    // We are using hand and plane anchors
    let configuration = SpatialTrackingSession.Configuration(tracking: [.hand, .plane])

    await trackingSession.run(configuration)
}

We can call this function in a task.

.task {
  await runTrackingSession()
}

Spatial Tracking Session will enable features on Anchoring Components. We can access the transform of these anchors, enable collisions, and use physics.

These anchors can be useful if we know about the anchors ahead of time. For example, we might know that we want to anchor an entity to an index finger. We can define an anchor that will activate when visionOS detects a finger tip.

We can do the same thing with planes. We can create an anchor and describe its characteristics. These include a horizontal surface classified as a floor of at least a certain size. When a plane is detected with these characteristics, an entity will be anchored to it.

However, these anchors don’t seem to offer control of placement or position. In the video demo, you can see the system creating the floor anchor. The position it uses is entirely arbitrary. It doesn’t place the entity in the center of the floor plane. † If you know a good way to solve this, please leave a comment below. We’ll dive further into this in later examples.

† I can visualize this plane using the Xcode debugging tools

Full example code

struct Example031: View {

    // 1. Create a session
    @State var trackingSession: SpatialTrackingSession = SpatialTrackingSession()

    var body: some View {
        RealityView { content in

            if let scene = try? await Entity(named: "AnchorLabs", in: realityKitContentBundle) {
                content.add(scene)

                // 3. FloorEntity has an anchoring component defined in Reality Composer Pro
                if let floorEntity = scene.findEntity(named: "FloorEntity") {
                    if var anchor = floorEntity.components[AnchoringComponent.self] {
                        // We need to clear the default physics simulation to let our sphere collide with this anchor
                        anchor.physicsSimulation = .none
                        floorEntity.components.set(anchor)
                    }
                }


                // 4. The hand anchor is created here, with the left hand sphere added as a child
                if let leftHandSphere = scene.findEntity(named: "LeftHand") {

                    let leftHand = AnchorEntity(.hand(.left, location: .indexFingerTip),
                                                trackingMode: .continuous)
                    leftHand.name = "LeftHandAnchor"
                    leftHand.addChild(leftHandSphere.clone(recursive: true))
                    leftHandSphere.position = .zero

                    leftHand.anchoring.physicsSimulation = .none
                    content.add(leftHand)

                }

                // 5. We can listen for anchor state changes
                _ = content.subscribe(to: SceneEvents.AnchoredStateChanged.self)  { event in
                    print("**anchor changed** \(event)")
                }
            }

        }
        .modifier(DragGestureImproved()) // just here to let me grap the sphere if it gets too far away
        .task {
            await runTrackingSession()
        }
    }

    // 2. Configure and run the session
    func runTrackingSession() async {
        // We are using hand and plane anchors
        let configuration = SpatialTrackingSession.Configuration(tracking: [.hand, .plane])

        await trackingSession.run(configuration)
    }

}

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?