iosswiftaugmented-realityarkit

How to tell which reference object was detected?


I have an ARKit application that detects a myriad of objects and then places 3d objects above them. I would like to change the text of the 3d object displayed above the detected objects, but can't figure out how to perform x function if y object is detected.

My collection of AR scans / objects is in a group called "gallery" and my code looks like this:

class ViewController: UIViewController, ARSCNViewDelegate {
    @IBOutlet var sceneView: ARSCNView!
    var arrowAnchor:ARAnchor?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Set the view's delegate
        sceneView.delegate = self
        sceneView.showsStatistics = true
        sceneView.autoenablesDefaultLighting = true
        sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        //Create ARWorldTrackingConfiguration object and load your garrey asset group.
        //You can add multiple ARObject file into ar asset group,
        let configuration = ARWorldTrackingConfiguration()
        guard let referenceObjects = ARReferenceObject.referenceObjects(inGroupNamed: "gallery", bundle: nil) else {
            fatalError("Missing expected asset catalog resources.")
        }
        configuration.detectionObjects = referenceObjects
        sceneView.session.run(configuration)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    }

    func session(_ session: ARSession, didFailWithError error: Error) {
        // Present an error message to the user
    }

    func sessionWasInterrupted(_ session: ARSession) {
        // Inform the user that the session has been interrupted, for example, by presenting an overlay
    }

    func sessionInterruptionEnded(_ session: ARSession) {
        // Reset tracking and/or remove existing anchors if consistent tracking is required
    }

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        if let objectAnchor = anchor as? ARObjectAnchor {
            let translation = objectAnchor.transform.columns.3
            let pos = float3(translation.x, translation.y, translation.z)
            let nodeArrow = getArrowNode()
            nodeArrow.position = SCNVector3(pos)
            nodeArrow.constraints = [SCNBillboardConstraint()]
            sceneView.scene.rootNode.addChildNode(nodeArrow)

            let text = SCNText(string: "Asset", extrusionDepth: 1)
            let material = SCNMaterial()
            material.diffuse.contents = UIColor.white
            text.materials = [material]
            let node = SCNNode()
            let pos2 = float3(translation.x-0.01, translation.y+0.22, translation.z-0.0)
            node.position = SCNVector3(pos2)
            node.scale = SCNVector3(x: 0.003, y: 0.003, z: 0.003)
            node.geometry = text
            node.constraints = [SCNBillboardConstraint()]
            sceneView.scene.rootNode.addChildNode(node)

        }
    }

    func getArrowNode() -> SCNNode {
        let sceneURL = Bundle.main.url(forResource: "arrow_yellow", withExtension: "scn", subdirectory: "art.scnassets")!
        let referenceNode = SCNReferenceNode(url: sceneURL)!
        referenceNode.load()
        return referenceNode
    }

    func getTextNode() -> SCNNode {
        let sceneURL = Bundle.main.url(forResource: "text", withExtension: "scn", subdirectory: "art.scnassets")!
        let referenceNode = SCNReferenceNode(url: sceneURL)!
        referenceNode.load()
        return referenceNode
    }

}

How can have certain code blocks execute depending on which reference object was detected?


Solution

  • This little magic incantation does exactly what I needed:

        let objectName = objectAnchor.referenceObject.name
    

    I used the code like this:

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        if let objectAnchor = anchor as? ARObjectAnchor {
            
            let objectName = objectAnchor.referenceObject.name
            
            let translation = objectAnchor.transform.columns.3
            let pos = float3(translation.x, translation.y, translation.z)
            let nodeArrow = getArrowNode()
            nodeArrow.position = SCNVector3(pos)
            nodeArrow.constraints = [SCNBillboardConstraint()]
            sceneView.scene.rootNode.addChildNode(nodeArrow)
            
            let text = SCNText(string: objectName, extrusionDepth: 1)
            let material = SCNMaterial()
            material.diffuse.contents = UIColor.white
            text.materials = [material]
            let node = SCNNode()
            let pos2 = float3(translation.x-0.01, translation.y+0.22, translation.z-0.0)
            node.position = SCNVector3(pos2)
            node.scale = SCNVector3(x: 0.003, y: 0.003, z: 0.003)
            node.geometry = text
            node.constraints = [SCNBillboardConstraint()]
            sceneView.scene.rootNode.addChildNode(node)
            
        }
    }