【问题标题】:ARKit Adding node causes frame drop even after using `prepare`即使在使用“准备”之后,ARKit 添加节点也会导致丢帧
【发布时间】:2018-11-20 07:11:31
【问题描述】:

我正在向我之前从互联网下载的场景添加一个包含动画的3D model。在添加这个node 之前,我使用prepare 函数,因为我不想避免丢帧。但我仍然得到一个非常短的帧下降到大约 47 fps。这是由执行此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


    【解决方案1】:

    我遇到了同样的问题。我的节点都在利用基于物理的渲染 (PBR),当我第一次向场景添加节点时,帧速率显着下降,但在那之后就很好了。我可以添加尽可能多的其他节点而不会降低帧率。

    我想出了一个解决这个问题的方法。我所做的是在创建 ARConfiguration 之后,在调用 session.run(configuration) 之前,将带有 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()。

    【讨论】:

    • 这确实有点帮助,但还不够。我之前尝试过添加这样的节点,这消除了addChildNode 中的卡顿,但prepare 仍然会导致卡顿。我通过在prepare 之后延迟addChildNode 5 秒来测试这一点。当我第一次在新模型上使用准备时,总是会出现这种短帧丢失。如何测试执行prepare 时发生的情况?也许这个模型有问题是什么原因造成的?不应该因为它在其他线程上运行而不会导致口吃吗?
    • 您找到更多相关信息了吗?在加载带有图像作为漫反射内容的平面时,我看到了同样的问题。我试过使用准备,但它没有帮助。我读过很多关于这种短帧停顿的报道。他们中的许多人像我一样只在第一次添加节点时发生。但对我来说,我无法通过预先添加来找到解决方法......这个理论是因为节点必须出现在相机中才能加载......这就是我读过的,这就是我正在经历的:)
    【解决方案2】:

    首先

    为 AR 应用获取不超过 10K 多边形和 1K x 1K 纹理的 3D 模型。每个模型使用 5K...7K 多边形可以实现最佳结果。总的来说,SceneKit 的场景可能包含not more than 100K polygons。此建议可帮助您显着提高渲染性能,并且我想您的丢帧率将降至最低。

    其次

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

    例如,您可以阅读此useful post,了解如何为AVCaptureSession 使用金属渲染。如何使用 Metal 的工作流程很棒。

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

    【讨论】:

    • 我真的希望继续使用 SceneKit 渲染器。几分之一秒后,帧率又回到了 60。我在想在添加节点之前使用准备可以解决这个问题,也许我以某种方式使用它错误或者我缺少一些东西。添加节点和准备节点都会导致这种短暂的卡顿。
    • @Andy,Damian - 我有同样的问题,不管我是否使用准备方法来添加节点。当模型第一次可见时,总是会出现帧率卡顿。我在某处读到这与着色器预编译有关。真的没有办法告诉 skenekit 预编译/预加载渲染目标节点所需的所有必需(内置)着色器。似乎如果一个人使用 SCNProgram 来代替,这可以解决问题 - 是的 - 但是如何获得 Apple PBR 着色器作为 SCNProgram?有什么新的好主意吗?
    • @Andy - 在我的实际情况中,我有一个包含模型的场景,该模型最初是一个 DAE 文件,我将其转换为 SCN。该模型非常简单,原始文件的大小甚至不超过 100 kB。附有一些材质(漫反射、金属、法线、粗糙度和 AO)。每个纹理文件的大小为 512x512 8 位 RGB 或灰度。该模型在渲染器进入相机截锥体后立即将其冻结 0.75 秒。我只是没有想法,我能做什么,不让这个丢帧。第一次显示模型时会发生丢帧。
    • @ZAY,在通过 Xcode(连接设备)编译的应用程序中会发生冻结,还是在您纯粹在 iPhone 上启动应用程序时发生冻结?
    • @Andy - 我对当前项目进行了第一次备份,将其剥离并添加了 Demonstration 对象。如果您想玩它,只需安装应用程序,启动并与角色一起走到右侧。演示对象进入相机平截头体并发生冻结。在代码中搜索 ANDY,您将立即看到内容在哪里。 (忽略其他代码,在这个例子中它根本没有组织)你可以在这里下载它:drive.google.com/file/d/1ciu-oN-_FCwodj6WHEBmnr-UCwNrv4fM/…
    猜你喜欢
    • 2018-11-25
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 2019-05-24
    • 2020-08-15
    相关资源
    最近更新 更多