Search code examples
swiftaugmented-realityscenekitarkit

How to capture node from "renderer(_:nodeFor:)" instance method?


I'm confused about this delegate method that is called when planeDetection is active. The method is being successfully called when plane is detected, but where does the returned SCNNode go? How do I access it?

func renderer(_ renderer: SCNSceneRenderer, 
          nodeFor anchor: ARAnchor) -> SCNNode? 

For what it's worth, I'm using a custom ARCL library that allows me to place nodes by GPS coordinates. For some reason, with that framework this method does not seem to be firing upon detecting a plane. My delegates are set properly because the renderer(_:nodeFor:) method does get called - otherwise I would just use this method.

func renderer(_ renderer: SCNSceneRenderer, 
             didAdd node: SCNNode, 
              for anchor: ARAnchor) 

Solution

  • Telling about new SCNNode, that renderer(_:nodeFor:) instance method generates for us, we pass this node to ARKit that tethers it with a corresponding anchor to thoroughly track its position.

    The node, returned by renderer(_:nodeFor:) method, added as a child to SCNScene root node. Quite often renderer(_:nodeFor:) method is used when tracking ARFaceAnchors.

    var specialNode: SCNNode?
    
    func renderer(_ renderer: SCNSceneRenderer, 
              nodeFor anchor: ARAnchor) -> SCNNode? {
    
        guard let sceneView = renderer as? ARSCNView, anchor is ARFaceAnchor 
        else { return nil }
    
        let faceGeometry = ARSCNFaceGeometry(device: sceneView.device!)!  
        self.specialNode = SCNNode(geometry: faceGeometry)
    
        return self.specialNode
    }
    

    ...

    func renderer(_ renderer: SCNSceneRenderer,
              didUpdate node: SCNNode,
                  for anchor: ARAnchor) {
        
        if let faceAnchor = anchor as? ARFaceAnchor,
           let faceGeo = node.geometry as? ARSCNFaceGeometry {
    
            faceGeo.update(from: faceAnchor.geometry)
        }
    }
    

    Nevertheless, you can use renderer(_:nodeFor:) method with any desired anchor type.