swiftswiftuiarkitrealitykitvisionos

Calculate distance between vision OS camera and 3D model in Vision OS


I'm working on a sample app in Vision OS where the app loads a 3D model of a city in full immersive space.

After loading, the user can navigate to different parts of the city like going towards a building or a tree etc.

I need to know if the user moves closer to a particular building; I need to log a message in the console (ex - "you have arrived").

From the documentation and through How to know user's position in Surrounding Space in visionOS, I'm able to find the location of the device in 3D space, but how do I calculate distance b/w device and particular building in 3D space?


Solution

  • The distance between two objects in 3D space can be calculated using the Pythagorean theorem, taking into account all three axes. Use the formula:

    d = √( (x2-x1)² + (y2-y1)² + (z2-z1)² )
    

    Here's the code:

    import SwiftUI
    import RealityKit
    import ARKit
    
    extension simd_float4 {
        var xyz: simd_float3 {
            return simd_float3(x, y, z)
        }
    }
    

    @Observable class CameraAnchorUpdater {
        let session = ARKitSession()
        let worldTracking = WorldTrackingProvider()
    
        func runSession() async {
            Task {
                try? await session.run([worldTracking])
            }
        }
        func getMatrix() -> simd_float4x4 {
            guard let mtx = worldTracking
                             .queryDeviceAnchor(atTimestamp: CACurrentMediaTime())
            else { return .init() }
                
            return mtx.originFromAnchorTransform
        }
    }
    

    struct ContentView : View {
        var cau = CameraAnchorUpdater()
        let head = try! Entity.load(named: "head")
        
        func updatingSceneEventsWith(_ content: RealityViewContent) {
            _ = content.subscribe(to: SceneEvents.Update.self) { _ in
                let cameraPosition = cau.getMatrix().columns.3.xyz
                 
                let x2 = cameraPosition.x    // x2
                let x1 = head.position.x     // x1      
                let y2 = cameraPosition.y    // y2
                let y1 = head.position.y     // y1               
                let z2 = cameraPosition.z    // z2
                let z1 = head.position.z     // z1
                
                let distance = sqrtf( (x2-x1) * (x2-x1) +
                                      (y2-y1) * (y2-y1) +
                                      (z2-z1) * (z2-z1) ) - 1.23
                
                let formatted = String(format: "%.2f m", arguments: [distance])
                print("Distance from camera to model is:", formatted)
            }
        }
        var body: some View {
            RealityView { content in
                content.add(head)
                updatingSceneEventsWith(content)
            }
            .task {
                await cau.runSession()
            }
        }
    }
    

    Additionally, you can use raycasting to calculate a distance from camera to model.