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

问题描述 投票:4回答:2

我正在添加一个包含动画的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
}
swift scenekit augmented-reality arkit frame-rate
2个回答
0
投票

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

例如,你可以阅读这个useful post关于使用金属渲染AVCaptureSession。如何使用Metal有很棒的工作流程。

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


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

© www.soinside.com 2019 - 2024. All rights reserved.