iosswiftarkitsknode

How to add node relative to tracked image position with ARKit?


When an image is detected, I add a node in front of it.

Image - what i need garantee

The node is this picture and in relation to this picture I add other nodes, one above (1) of the picture and another next (2). Node 1 always gets in the correct position, but node 2 sometimes gets in front of the image, which is wrong, and sometimes gets in the right position that it's like the photo.

Image - wrong

for anchor in sceneView.session.currentFrame!.anchors {
     let imageAnchor = anchor as! ARImageAnchor
     nodeInformation.position = SCNVector3Make(imageAnchor.transform.columns.3.x/100, imageAnchor.transform.columns.3.y/100 + 0.3, imageAnchor.transform.columns.3.z/100) //node 1
     nodeAuthorInformation.position = SCNVector3Make(imageAnchor.transform.columns.3.x/100 + 0.3, imageAnchor.transform.columns.3.y/100, imageAnchor.transform.columns.3.z/100) //node 2

This is the code that I'm using to set the initial position of my two nodes.

So i would like to know how i can garantee that my second node will stay always in the right position, that it is next to picture.

How I add the nodes:

let tappedNode = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [:])

        if let result = tappedNode.first{
            nodeInformation.transform = result.modelTransform
            nodeAuthorInformation.transform = result.modelTransform
        }
        print("TAP PLACE = ", gesture.location(in: gesture.view))
        if !tappedNode.isEmpty{
            let node = tappedNode[0].node
            print("NODE TAP = ", node.position)
            let artPlane = SCNPlane(width: 0.3, height: 0.3)

            artPlane.firstMaterial?.diffuse.contents = arArtDetailsScene
            artPlane.firstMaterial?.isDoubleSided = true

            let planeNode = SCNNode(geometry: artPlane)
            planeNode.eulerAngles.x = .pi

            authorPlane = SCNPlane(width: 0.2, height: 0.3)
            authorPlane.firstMaterial?.diffuse.contents = arAuthorDetailsScene
            authorPlane.firstMaterial?.isDoubleSided = true

            let planeAuthorNode = SCNNode(geometry: authorPlane)
            planeAuthorNode.eulerAngles.x = .pi

            nodeInformation.addChildNode(planeNode)
            nodeAuthorInformation.addChildNode(planeAuthorNode)
            changeArtDetails(artId: artIndex + 1)

            sceneView.scene.rootNode.addChildNode(nodeInformation)
            sceneView.scene.rootNode.addChildNode(nodeAuthorInformation)
            if sceneView.session.currentFrame != nil {
                for anchor in sceneView.session.currentFrame!.anchors {
                    let imageAnchor = anchor as! ARImageAnchor
                    nodeInformation.position = SCNVector3Make(imageAnchor.transform.columns.3.x/100, imageAnchor.transform.columns.3.y/100 + 0.3, imageAnchor.transform.columns.3.z/100) // initial position node 1
                    nodeAuthorInformation.position = SCNVector3Make(imageAnchor.transform.columns.3.x/100 + 0.3, imageAnchor.transform.columns.3.y/100, imageAnchor.transform.columns.3.z/100) // initial position node 2
                }
            }

And I update the position of the node like this:

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

    if sceneView.session.currentFrame != nil {
        for anchor in sceneView.session.currentFrame!.anchors {
            if let imageAnchor = anchor as? ARImageAnchor{
                DispatchQueue.main.async {

                    self.nodeInformation.position = SCNVector3Make(imageAnchor.transform.columns.3.x/100, imageAnchor.transform.columns.3.y/100 + 0.3, imageAnchor.transform.columns.3.z/100)
                    self.nodeAuthorInformation.position = SCNVector3Make(self.nodeInformation.position.x + 0.3, self.nodeInformation.position.y - 0.3, self.nodeInformation.position.z)//SCNVector3Make(imageAnchor.transform.columns.3.x/100 + 0.3, imageAnchor.transform.columns.3.y/100, imageAnchor.transform.columns.3.z/100)

                }
            } 
        }
    }
}

Solution

  • ARKit updates position of anchors, not nodes. You will need to provide a node with three custom nodes as children in ARSCNViewDelegate.renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? if anchor is ARImageAnchor instead of adding it manually to the scene.