3

What I want to achieve: Attach a sphere to the camera position (so that it always stay at the center of the screen as the device move) and detect when it is on top of other AR objects - to trigger other actions/behaviour on the AR objects.

Approach: I have created the sphere and attached to the center of the screen as shown below

@IBOutlet var arView: ARView!

override func viewDidLoad() {
    super.viewDidLoad()

    let mesh = MeshResource.generateSphere(radius: 0.1)
    let sphere = ModelEntity(mesh: mesh)

    let anchor = AnchorEntity(.camera)

    sphere.setParent(anchor)
    arView.scene.addAnchor(anchor)

    sphere.transform.translation.z = -0.75
}

Next step, perform a hittest or a raycast in session(_:didUpdate:)

 let results = arView.hitTest(CGPoint(x: 0.5, y: 0.5), query: .all, mask: .default)
//normalised center ; 2D position of the camera (our sphere) in the view’s coordinate system

But I am constantly getting ground plane as my result with this approach. Is there something I am missing or there is a different approach to achieving this

Note: Just in case there is something wrong I have created my basic scene as I want to track an image and add content on top of the image marker in Reality Composer and using the .rcproject in Xcode also have enabled collision property for all the overlaid items.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
anahom
  • 69
  • 4
  • Do your objects have a CollisionComponent? The documentation for hitTest says it’ll ignore entities that don’t have one. – EmilioPelaez Jan 20 '21 at 17:25
  • I have called `entity.generateCollisionShapes(recursive: true)` and also enabled **Physics->Collision shape** in Reality Composer. – anahom Jan 20 '21 at 17:42

1 Answers1

2

Try the following solution:

import ARKit
import RealityKit

class ViewController: UIViewController {
    
    @IBOutlet var arView: ARView!
    var sphere: ModelEntity?
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = arView.center
        let results: [CollisionCastHit] = arView.hitTest(touch)
        
        if let result: CollisionCastHit = results.first {
            if result.entity.name == "Cube" && sphere?.isAnchored == true {
                print("BOOM!")
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Crosshair
        let mesh01 = MeshResource.generateSphere(radius: 0.01)
        sphere = ModelEntity(mesh: mesh01)
        sphere?.transform.translation.z = -0.15
        let cameraAnchor = AnchorEntity(.camera)
        sphere?.setParent(cameraAnchor)
        arView.scene.addAnchor(cameraAnchor)
        
        // Model for collision
        let mesh02 = MeshResource.generateBox(size: 0.3)
        let box = ModelEntity(mesh: mesh02, materials: [SimpleMaterial()])
        box.generateCollisionShapes(recursive: true)
        box.name = "Cube"
        let planeAnchor = AnchorEntity(.plane(.any, 
                              classification: .any, 
                               minimumBounds: [0.2, 0.2]))
        box.setParent(planeAnchor)
        arView.scene.addAnchor(planeAnchor)
    }
}
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • Hello Andy, thanks for your prompt response. But this is when you want to check if you tapped on the cube. What I was trying to achieve is if there is already a sphere in the scene (placed at the camera location) I want to check if at any given time the ray from the sphere position intersects with the cube. Basically any time the camera is directly (looking at) in line with the cube. May be the way I am approaching it is wrong & there is a better way to get what the camera is directly looking at and if there are any AR object in its straight line view. I hope this makes my question clear – anahom Jan 20 '21 at 21:29
  • 1
    Thank you so very much. I just passed `touch = arView.center` in my code above and it works perfectly. Thank you again! – anahom Jan 20 '21 at 22:02