Search code examples
iosswiftarkitscntext

Displaying live information in 3d using arkit, possibly using scntext


I have been trying to get this to work for 3 days now. For my project I need to display changing values as 3d text rendered in an AR application written in Swift for iOS.

What I already found: I can use the following code to generate a static text in 3d at a certain location. I can put it in the ViewDidLoad method of my ViewController so that it loads once on startup.

let text = SCNText(string: "Let's begin!", extrusionDepth: 1)

//Create material
let material = SCNMaterial()
material.diffuse.contents = UIColor.green
text.materials = [material]

//Create Node object
let textNode = SCNNode()
textNode.scale = SCNVector3(x:0.004,y:0.004,z:0.004)
textNode.geometry = text
textNode.position = SCNVector3(x: 0, y:0.02, z: -0.5)

sceneView.scene.rootNode.addChildNode(textNode)

Now my problem is I cannot get it to change periodically and say count up to 10000.

I have tried quite a few ideas, but none showed the numbers counting up.

UPDATE: I am having trouble removing the node after I create it. Also I do not know exactly when I have to remove it.

I am receiving a bad access code=1 error. The problem seems to lie with the finding & removing the node, because if I comment the line the app launches. It may have sth to do with access privileges.

This is my function:

func updateSCNText2 (incomingInt: Int) {

    // create new text
    let text = SCNText(string: String(incomingInt), extrusionDepth: 1)
    //  create material
    let material = SCNMaterial()
    material.diffuse.contents = UIColor.green
    text.materials = [material]

    //Create Node object
    let textNode = SCNNode()
    textNode.name = "textNodeName"
    textNode.scale = SCNVector3(x:0.004,y:0.004,z:0.004)
    textNode.geometry = text
    textNode.position = SCNVector3(x: 0, y:0.02, z: -0.5)

    //  add new node to root node
    sceneView.scene.rootNode.addChildNode(textNode)

    //  find & remove previous node (childNodeWithName)
    sceneView.scene.rootNode.childNode(withName: "textNodeName", recursively: false)?.removeFromParentNode()

}

Where I am calling the function:

var k = 0

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

    print(k)
    updateSCNText2(incomingInt:  k)
    k = k+1
}

Thank you so much for taking the time!


Solution

  • Best way to do this is using NSTimer

    Firstly, set textNode & a counter var at the top of your ViewController class

    var textNode: SCNNode!
    
    var counter = 0
    

    inside of viewDidLoad add the NSTimer call:

    var timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
    

    leave you original textNode creation method in ViewDidLoad except textNode is now var

    this is the update function

    @objc func update() {
    
        counter += 1
    
        // remove the old textNode
    
        textNode.removeFromParentNode()
    
            // create new text
            let text = SCNText(string: String(counter), extrusionDepth: 1)
            //  create material
            let material = SCNMaterial()
            material.diffuse.contents = UIColor.green
            text.materials = [material]
    
            //Create Node object
        textNode = SCNNode()
        textNode.scale = SCNVector3(x:0.004,y:0.004,z:0.004)
        textNode.geometry = text
        textNode.position = SCNVector3(x: 0, y:0.02, z: -0.5)
    
        //  add new node to root node
        self.sceneView.scene.rootNode.addChildNode(textNode)
    
    }
    

    Note: this code works, just tested it out in a playground. Can provide if needed.