Search code examples
swiftaugmented-realityscenekitarkit

SceneKit / ARKit updating a node every frame


I'm working with ARKit / SceneKit and I'm trying to have an arrow point to an arbitrary position I set in the world, but I'm having a bit of trouble. In my sceneView I have a scene set up to load in my arrow.

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the view's delegate
        sceneView.delegate = self
        guard let arrowScene = SCNScene(named: "art.scnassets/arrowScene.scn") else {
            fatalError("Scene arrow.scn not found")
        }
        
        let worldAnchor = ARAnchor(name: "World Anchor", transform: simd_float4x4(1))
        sceneView.session.add(anchor: worldAnchor)
        
        sceneView.scene = (arrowScene)
    }

I wish to then use SCNNode.look(at:) to point my arrow at the specified anchor, however, I am unsure how to get this to occur every frame. I know that I have access to special delegates provided by ARSCNView such as renderer(willUpdate node:), but I am unsure how to use these when the anchor is not changing positions whereas the arrow is.

Thanks for the help!


Solution

  • You could do so by using the updateAtTime delegate function, but I strongly recommend you to use a SCNConstraint.

    let lookAtConstraint = SCNLookAtConstraint(target: myLookAtNode)
    lookAtConstraint.isGimbalLockEnabled = true // useful for cameras, probably also for your arrow.
    
    // in addition you can use a position constraint
    let positionConstraint = SCNReplicatorConstraint(target: myLookAtNode)
    positionConstraint.positionOffset           = yourOffsetSCNVector3
    positionConstraint.replicatesOrientation    = false
    positionConstraint.replicatesScale          = false
    positionConstraint.replicatesPosition       = true
        
    // then add the constraints to your arrow node
    arrowNode.constraints = [lookAtConstraint, positionConstraint ]
    

    This will automatically adjust your node for each rendered frame.