ios – 带有ARSCNView的UIViewController在屏幕上呈现之前需要很长时间

ios – 带有ARSCNView的UIViewController在屏幕上呈现之前需要很长时间,第1张

概述我有一个UIViewController,它使用ARSCNView并通过Scenekit向它添加一些元素,如下例所示.一切都工作正常,除非我打电话给当前显示这个视图控制器,它需要很长的时间或延迟才能在屏幕上显示. @IBOutlet var sceneView: ARSCNView!override func viewDidLoad() { super.viewDidLoad() 我有一个UIVIEwController,它使用ARSCNVIEw并通过Scenekit向它添加一些元素,如下例所示.一切都工作正常,除非我打电话给当前显示这个视图控制器,它需要很长的时间或延迟才能在屏幕上显示.

@IBOutlet var sceneVIEw: ARSCNVIEw!overrIDe func vIEwDIDLoad() {    super.vIEwDIDLoad()    sceneVIEw.showsstatistics =  DeBUGSettings.isDeBUGActive    for (index,coach) in coachpositions.enumerated() {        let coachGeometry = SCNBox(wIDth: 0.1,height: 0.1,length: 0.1,chamferRadius: 0.005)        let coachNode = TrainEngineNode(position:  SCNVector3Make(0,float(index) * 0.1,-0.5),geometry: coachGeometry)        sceneVIEw.scene.rootNode.addChildNode(coachNode)    }    self.sceneVIEw.autoenablesDefaultlighting = true}overrIDe func vIEwWillAppear(_ animated: Bool) {    super.vIEwWillAppear(animated)    // Create a session configuration    let configuration = ARWorldTrackingConfiguration()    // Run the vIEw's session    sceneVIEw.session.run(configuration)}
解决方法 正如大家所指出的那样,延迟是你在设置场景时阻塞主线程的事实.所有UI更新都发生在主线程上,并且显示刷新 60 times per second,除了可以做120Hz的最新iPad专业版.这意味着您所执行的任何同步工作单元必须在不到1/60 = 0.016667秒内完成.

您的初始化程序TrainEngineNode(position:geometry :)可能正在执行诸如从DAE或OBJ文件加载资源的工作,这可能是所有时间的所在.我这样说,因为如果你改变这一行:

let coachNode = TrainEngineNode(position:  SCNVector3Make(0,geometry: coachGeometry)

为此,我需要这样做,因为你的问题中没有提供TrainEngineNode:

let coachNode = SCNNode(geometry: coachGeometry)

那么iPhone 7没有明显的延迟.

SceneKit和ARKit不要求您对任何特定线程进行更改,因此只要您遇到这种情况,您就可以将工作卸载到后台队列,或者最好是您管理的串行队列.在适当的时间进行工作有一些注意事项,例如在ARSession完全运行后将对象添加到场景中.对于创建ARKit应用程序时可能遵循的模式的一些优秀想法,我推荐Apple提供的this sample.

简化示例如下:

class SimpleARVIEwController: UIVIEwController {    @IBOutlet weak var sceneVIEw: ARSCNVIEw!    weak var activityIndicator: UIActivityIndicatorVIEw?    var coachpositions = [1,2,3,4,5]    let updateQueue = dispatchQueue(label: "com.example.apple-samplecode.arkitexample.serialSceneKitQueue")    overrIDe func vIEwDIDLoad() {        super.vIEwDIDLoad()        sceneVIEw.Alpha = 0        vIEw.backgroundcolor = .black        sceneVIEw.isPlaying = false        sceneVIEw.session.delegate = self        let activityIndicator = UIActivityIndicatorVIEw(activityIndicatorStyle: .whiteLarge)        activityIndicator.startAnimating()        activityIndicator.translatesautoresizingMaskIntoConstraints = false        vIEw.addSubvIEw(activityIndicator)        NSLayoutConstraint.activate([vIEw.centerXAnchor.constraint(equalTo: activityIndicator.centerXAnchor,constant: 0),vIEw.centerYAnchor.constraint(equalTo: activityIndicator.centerYAnchor,constant: 0)])        self.activityIndicator = activityIndicator        sceneVIEw.autoenablesDefaultlighting = true    }    private func loadScene() {        SCNTransaction.begin()        SCNTransaction.disableActions = true        for (index,_) in self.coachpositions.enumerated() {            let coachGeometry = SCNBox(wIDth: 0.1,chamferRadius: 0.005)            // Simulates loading time of `TrainEngineNode(position:geometry:)`            usleep(500000)            let coachNode = SCNNode(geometry: coachGeometry)            coachNode.worldposition = SCNVector3Make(0,-0.5)            self.sceneVIEw.scene.rootNode.addChildNode(coachNode)        }        SCNTransaction.commit()        self.isLoading = false    }    overrIDe func vIEwWillAppear(_ animated: Bool) {        super.vIEwWillAppear(animated)        let configuration = ARWorldTrackingConfiguration()        sceneVIEw.session.run(configuration)    }    overrIDe func vIEwWilldisappear(_ animated: Bool) {        super.vIEwWilldisappear(animated)        sceneVIEw.session.pause()    }    var isLoading = true    var hasLoaded = false}extension SimpleARVIEwController: ARSessionDelegate {    func session(_ session: ARSession,dIDUpdate frame: ARFrame) {        // Waiting until after the session starts prevents objects from jumPing around        if hasLoaded == false {            hasLoaded = true            updateQueue.async { [weak self] in                self?.loadScene()            }        } else if isLoading == false {            guard let activityIndicator = self.activityIndicator else { return }            dispatchQueue.main.async {                UIVIEw.animate(withDuration: 0.35,animations: { [weak self] in                    self?.sceneVIEw.Alpha = 1                    activityIndicator.Alpha = 0                },completion: { _ in                    activityIndicator.removeFromSupervIEw()                })            }        }    }}

此代码导致以下交互:

正如您在gif中看到的那样,视图控制器显示没有延迟,因为所有加载“工作”现在都在我们的专用串行队列上完成.通过将TrainEngineNode的创建与它们添加到场景的时间分离,可以进一步改善这个人为的例子.为了简洁起见,我保持逻辑与您已经拥有的逻辑类似,同时提供相对强大的初始化.对于3D对象加载的更强大/抽象的实现,我建议查看VirtualObjectLoader以及它在上述示例项目中的使用方式.

总结

以上是内存溢出为你收集整理的ios – 带有ARSCNView的UIViewController在屏幕上呈现之前需要很长时间全部内容,希望文章能够帮你解决ios – 带有ARSCNView的UIViewController在屏幕上呈现之前需要很长时间所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1008475.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存