Search code examples
iosswiftaugmented-realityscenekitarkit

Swift: Obtain and save the updated SCNNode over time using projectPoint in scenekit


I am trying to use projectPoint to get the 2D information of the updated SCNNode in scenekit and save them.

Based on ignotusverum's suggestion, I am able to save the SCNNode in to a path in a button.

     var lastPosition: CGPoint?
     func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
            guard anchor == currentFaceAnchor,
                let contentNode = selectedContentController.contentNode,
                contentNode.parent == node
                else { return }
            for (index, vertex) in vertices.enumerated() {
            let vertex = sceneView.projectPoint(node.convertPosition(SCNVector3(vertex), to: nil))
            let xVertex = CGFloat(vertex.x)
            let yVertex = CGFloat(vertex.y)
            Position = CGPoint(x: xVertex, y: yVertex)
           }
            selectedContentController.session = sceneView?.session
            selectedContentController.sceneView = sceneView
            selectedContentController.renderer(renderer, didUpdate: contentNode, for: anchor)
        }

Started saving via a start button:

    private var fpsTimer = Timer()
    private var currentCaptureFrame = 0
    @IBAction private func startPressed() {
        currentCaptureFrame = 0 //inital capture frame
        fpsTimer = Timer.scheduledTimer(withTimeInterval: 1/fps, repeats: true, block: {(timer) -> Void in self.recordData()})
    }

Saved them via a stop button clicks:

@IBAction private func stopPressed() {
    do {
        fpsTimer.invalidate() //turn off the timer
        let capturedData = captureData.map{$0.stringRepresentation}.joined(separator:"\(lastPosition)>")
        let dir: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! as URL
        let url = dir.appendingPathComponent("testing.txt")
        try capturedData.appendLineToURL(fileURL: url as URL)
    }
    catch {
        print("Could not write to file")
    }
}

So far works fine with the points being saved. The problem is that in the saved data, I realized the data is only saving one frame of the x and y vertices. For example:

[(411.0618591308594, 534.4215087890625), (410.7286071777344, 544.9381713867188), (411.5425720214844, 522.1063232421875), (412.0340881347656, 512.1854248046875),... 

[(411.0618591308594, 534.4215087890625), (410.7286071777344, 544.9381713867188), (411.5425720214844, 522.1063232421875), (412.0340881347656, 512.1854248046875)

The data is repeating with one frame rather than the period I want to save from the moment when I click start button to stop button.

My question is how to save the updated SCNNode over time from the moment when I click start button to stop button?

Thanks in advance!


Solution

  • If I understand your question correctly you want to save the vertex positions each time they are updated, keeping track of all previous updates as well as the most recent one. In order to do this you simply need to append the new vertex position array to the global array with saved data.

     var savedPositions = [CGPoint]()
     var beginSaving = false
    
     func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
            guard anchor == currentFaceAnchor,
                let contentNode = selectedContentController.contentNode,
                contentNode.parent == node
                else { return }
            for vertex in vertices {
                let projectedPoint = sceneView.projectPoint(node.convertPosition(SCNVector3(vertex), to: nil))
                if beginSaving {
                   savedPositions.append(CGPoint(x: projectedPoint.x, y: projectedPoint.y))
                }
            }
            selectedContentController.session = sceneView?.session
            selectedContentController.sceneView = sceneView
            selectedContentController.renderer(renderer, didUpdate: contentNode, for: anchor)
    }
    
    @IBAction private func startPressed() {
        beginSaving = true
    }
    
    @IBAction private func stopPressed() {
        beginSaving = false
        ....//do whatever with your array of saved positions
    }