Swift: получение и сохранение обновленного SCNNode с течением времени с помощью projectPoint в Scenekit. - PullRequest
2 голосов
/ 04 августа 2020

Я пытаюсь использовать projectPoint, чтобы получить 2D-информацию обновленного SCNNode в Scenekit и сохранить их.

На основе предложения ignotusverum я могу сохранить SCNNode в пути в кнопка.

     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)
        }

Начат сохранение с помощью кнопки запуска:

    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()})
    }

Сохраняет их через нажатие кнопки остановки:

@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")
    }
}

Пока работает нормально с сохранением точек. Проблема в том, что в сохраненных данных я понял, что данные сохраняют только один кадр вершин x и y. Например:

[(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)

Данные повторяются с одним кадром, а не с периодом, который я хочу сохранить, с момента, когда я нажимаю кнопку запуска до кнопки остановки.

Мой вопрос как сохранить обновленный SCNNode с течением времени с момента, когда я нажимаю кнопку запуска до кнопки остановки?

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Если я правильно понял ваш вопрос, вы хотите сохранять позиции вершин каждый раз, когда они обновляются, отслеживая все предыдущие обновления, а также самое последнее. Для этого вам просто нужно добавить новый массив позиций вершин в глобальный массив с сохраненными данными.

 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
}
1 голос
/ 04 августа 2020

SceneKit вызывает этот метод ровно один раз за кадр. Если вы делаете что-то внутри рендерера, вам нужно «сделать это» и уйти, иначе это может повлиять на FPS.

Если вам нужно переместить или проверить много l oop вещей, вы можете использовать таймеры для выполнения этих действий по отдельности, что позволяет вам в некоторой степени контролировать их. Вы по-прежнему можете поддерживать свой FPS на высоком уровне и разрывать циклы или работать по частям в таймерах. Если вы это сделаете, просто убедитесь, что вы поместили таймеры в основной поток.

Вы также можете посмотреть: node.presentation, ie: свойства отражают временные значения, определяемые любыми анимациями в полете, которые в настоящее время влияют узел.

...