即使在使用`prepare`之后,ARKit添加节点也会导致帧丢失

时间:2018-06-11 05:16:28

标签: swift scenekit augmented-reality arkit frame-rate

我正在向我之前从互联网上下载的场景中添加一个包含动画的3D model。在添加此node之前,我在其上使用prepare函数,因为我不想避免丢帧。但是我仍然得到一个非常短的帧下降到大约47帧/秒。这是由执行此prepare函数引起的。我也尝试在其他调度队列上使用prepare(_:, shouldAbortBlock:),但这仍然没有帮助。有人可以帮我解决这个问题,或者告诉我为什么会发生这种情况?

arView.sceneView.prepare([mediaNode]) { [mediaNode, weak self] (success) in
    guard let `self` = self else { return }
    guard
        let currentMediaNode = self.mediaNode as? SCNNode,
        currentMediaNode === mediaNode,
        !self.mainNode.childNodes.contains(mediaNode)
        else { return }
    self.mainNode.addChildNode(mediaNode)
}

顺便说一下,这是我用来加载此模型的文件列表:

https://www.dropbox.com/s/7968fe5wfdcxbyu/Serah-iOS.dae?dl=1
https://www.dropbox.com/s/zqb6b6rxynnvc5e/0001.png?dl=1
https://www.dropbox.com/s/hy9y8qyazkcnvef/0002.tga?dl=1
https://www.dropbox.com/s/fll9jbjud7zjlsq/0004.tga?dl=1
https://www.dropbox.com/s/4niq12mezlvi5oz/0005.png?dl=1
https://www.dropbox.com/s/wikqgd46643327i/0007.png?dl=1
https://www.dropbox.com/s/fioj9bqt90vq70c/0008.tga?dl=1
https://www.dropbox.com/s/4a5jtmccyx413j7/0010.png?dl=1

DAE文件已由Xcode工具编译,因此可以在从Internet下载后加载。这是我用来在下载后加载它的代码:

class func loadModel(fromURL url: URL) -> SCNNode? {
    let options = [SCNSceneSource.LoadingOption.animationImportPolicy : SCNSceneSource.AnimationImportPolicy.playRepeatedly]
    let sceneSource = SCNSceneSource(url: url, options: options)
    let node = sceneSource?.entryWithIdentifier("MDL_Obj", withClass: SCNNode.self)
    return node
}

2 个答案:

答案 0 :(得分:0)

ARKit / SceneKit / AVKit中删除丢帧的最简单方法是使用Metal框架。试想一下:与基于CPU的等效过滤器相比,简单的图像过滤器在GPU上的执行速度要快一百倍。关于实时AV视频和3D动画,我可以说同样的事情 - 它们在GPU上表现得更好。

例如,您可以阅读useful post关于使用AVCaptureSession的金属渲染的信息。如何使用Metal,这是一个非常棒的工作流程。

P.S。在编写代码之前,请在3D创作工具中检查您的动画对象/场景(如果没问题)。

答案 1 :(得分:0)

我遇到了同样的问题。我的节点都利用了基于物理的渲染(PBR),并且第一次将节点添加到场景时,帧速率显着下降,但之后很好。我可以在没有帧速率下降的情况下添加任意数量的其他节点。

我想出了解决这个问题的方法。我做的是在创建ARConfiguration之后,在调用session.run(配置)之前,我将带有PBR的测试节点添加到场景中。为了不显示该节点,我将节点的材质的colorBufferWriteMask设置为空数组(请参阅此答案:ARKit hide objects behind walls)然后,在添加内容之前,我删除该节点。添加和删​​除此测试节点对我来说非常有用。

以下是一个例子:

var pbrTestNode: SCNNode!

func addPBRTestNode() {
        let testGeometrie = SCNBox(width: 0.5, height: 0.5, length: 0.5, chamferRadius: 0)
        testGeometrie.materials.first?.diffuse.contents = UIColor.blue
        testGeometrie.materials.first?.colorBufferWriteMask = []
        testGeometrie.materials.first?.lightingModel = .physicallyBased
        pbrTestNode = SCNNode(geometry: testGeometrie)

        scene.rootNode.addChildNode(pbrTestNode)
    }

func removePBRTestNode() {
        pbrTestNode.removeFromParentNode()
    }

func startSessionWithPlaneDetection() {
        // Create a session configuration
        let configuration = ARWorldTrackingConfiguration()
        if #available(iOS 11.3, *) {
            configuration.planeDetection = [.horizontal, .vertical]
        } else {
            configuration.planeDetection = .horizontal
        }
        configuration.isLightEstimationEnabled = true

        // this prevents the delay when adding any nodes with PBR later
        sceneController.addPBRTestNode()

        // Run the view's session
        sceneView.session.run(configuration)
    }

将内容添加到场景时调用removePBRTestNode()。