swiftaugmented-realityarkitrealitykit

Get distance between the entity anchor and the camera


I'm adding a scene to my ARView that contains one entity. I was wondering how I would be able to get the distance between the entity's anchor and the camera. I know how to get the current position of the camera, but the position I'm getting for the arScene must be wrong since subtracting both positions doesn't yield the right position. Here is some code below.

import RealityKit

class ViewController: UIViewController, ARSessionDelegate {
  let arScene = try! TestProj.loadScene()
  @IBOutlet var sceneView: ARView!

  override func viewDidLoad() {
    ...
    sceneView.scene.addAnchor(arScene)
    ...
  }

  func session(_ session: ARSession, didUpdate frame: ARFrame) {
    // Calculate distance here
    let cameraPos = frame.camera.transform.columns.3
    let entityPos = // Position of entity's anchor
    let distance = // Find distance here
  }
}

Solution

  • You need to perform a Convex Raycast against all the geometry in the RealityKit's scene for a ray between two end points:

    import UIKit
    import RealityKit
    
    class ViewController: UIViewController {
    
        @IBOutlet var arView: ARView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let entity = ModelEntity(mesh: .generateBox(size: 0.4))
            entity.name = "Cube"
    
            let anchor = AnchorEntity(world: [0,0,0])
            anchor.addChild(entity)
            arView.scene.anchors.append(anchor)
        
            // For every entity that could be hit,
            // we must generate a collision shape.
            entity.generateCollisionShapes(recursive: true)
        }
    
        @IBAction func onTap(_ sender: UITapGestureRecognizer) {
    
            let query: CollisionCastQueryType = .nearest
            let mask: CollisionGroup = .default
    
            let camera = arView.session.currentFrame?.camera
            let x = (camera?.transform.columns.3.x)!
            let y = (camera?.transform.columns.3.y)!
            let z = (camera?.transform.columns.3.z)!
    
            let transform: SIMD3<Float> = [x, y, z]
               
            let raycasts: [CollisionCastHit] = arView.scene.raycast(
                                                               from: transform, 
                                                                 to: [0, 0, 0], 
                                                              query: query, 
                                                               mask: mask, 
                                                         relativeTo: nil)
        
            guard let raycast: CollisionCastHit = raycasts.first
            else { return }
        
            print(raycast.distance)     // Distance from the ray origin to the hit
            print(raycast.entity.name)  // The entity that was hit
            print(raycast.position)     // The position of the hit
        }    
    }
    

    Also, as @maxxfrazer suggested, you can access camera transforms more easily:

    let translate = arView.cameraTransform.translation
    
    let x = translate.x
    let y = translate.y
    let z = translate.z
    
    let transform: SIMD3<Float> = [x, y, z]