【问题标题】:ARKit Session Paused and Not ResumingARKit 会话已暂停且未恢复
【发布时间】:2023-04-03 12:25:01
【问题描述】:

在我的 ARKit 应用中,我展示了一个模态窗口。当我关闭模式并返回 ARSCNView 时,我发现会话由于以下代码而暂停:

 override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        // Pause the view's session
        sceneView.session.pause()
    } 

当我关闭模态并返回 ARKit 相机视图屏幕时,会触发以下代码:

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Create a session configuration
        let configuration = ARWorldTrackingSessionConfiguration()

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

但是这段代码永远不会恢复会话。屏幕在它读取的最后一张图像上完全冻结。有什么想法吗?

我将 viewDidAppear 代码更新为以下内容。它仍然卡在相机屏幕上,图像冻结。

  override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Create a session configuration
        let configuration = ARWorldTrackingSessionConfiguration()

        sceneView.session.delegate = self

        if self.isPaused {
            sceneView.session.run(sceneView.session.configuration!)
        } else {
            // Run the view's session
            sceneView.session.run(configuration)
        }


    }

【问题讨论】:

    标签: ios arkit


    【解决方案1】:

    不知道为什么你的会话没有恢复,但是......这通常不是你想要的情况。

    Apple 的 ARKit 示例代码附带的自述文件中的注意事项(附在 WWDC17 session on ARKit 上):

    避免中断 AR 体验。如果用户在您的应用中切换到另一个全屏 UI,返回时 AR 视图可能不是预期的状态。

    为辅助视图控制器使用弹出框演示(即使在 iPhone 上),以在调整设置或进行模式选择时让用户保持在 AR 体验中。在此示例中,SettingsViewControllerVirtualObjectSelectionViewController 类使用弹出框表示。

    更详细一点:如果您暂停会话,当您的用户不在另一个全屏视图控制器中时,它不会跟踪世界。这意味着当您恢复时,放置在场景中的任何虚拟内容都不会位于您离开它的位置(相对于相机)。

    【讨论】:

    【解决方案2】:

    我知道您选择了一个答案,并且该答案是苹果推荐的答案,您可以重新启动 AR Session。但是,您无法取消暂停/恢复会话,因为一旦您离开显示 ARSceneView 的控制器,设备就会停止跟踪,并且将停止跟踪您的设备相对于您放置在场景中的对象的位置.

    无论如何,我基本上通过销毁会话的所有方面并在我的视图重新出现时或通过按下按钮时重建它们来设法重新启动会话。

    我将在此处发布一些示例代码。它在 Objective-C 中,因为我的项目是用它编写的,但它可能会帮助未来有同样问题的人。

    -(void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated]
        [self setupScene];
        [self setupSession];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self destroySession];
        [self destroyScene];
    }
    
    - (void)setupScene {
    
    // Setup the ARSCNViewDelegate - this gives us callbacks to handle new
    // geometry creation
        self.sceneView.delegate = self;
    
    // A dictionary of all the current planes being rendered in the scene
        self.planes = [NSMutableDictionary new];
    
    // Contains a list of all the boxes rendered in the scene
        self.boxes = [NSMutableArray new];
    
    // Show statistics such as fps and timing information
        self.sceneView.showsStatistics = YES;
        self.sceneView.autoenablesDefaultLighting = YES;
    
        SCNScene *scene = [SCNScene new];
    
        [self.sceneView setScene:scene];
    
        self.sceneView.scene.physicsWorld.contactDelegate = self;   
    }
    
    - (void)setupSession {
    
        // Create a session configuration
        ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfiguration new];
        //ARWorldTrackingSessionConfiguration *configuration = [ARWorldTrackingSessionConfiguration new]; This has been deprecated in favor of the previous line in XCode 9 beta 5. 
    
        // Specify that we do want to track horizontal planes. Setting this will cause the ARSCNViewDelegate
        // methods to be called when scenes are detected
        //configuration.planeDetection = ARPlaneDetectionHorizontal;
    
        // Run the view's session
        [self.sceneView.session runWithConfiguration:configuration options:ARSessionRunOptionResetTracking];
    }
    
    
    -(void)destroyScene {
        bottomPlane = nil;
        [self.sceneView setScene:nil];
        [self.sceneView setDebugOptions:nil];
        self.boxes = nil;
        self.planes = nil;
        self.sceneView.delegate = nil;  
    }
    
    -(void)destroySession {
        [self.sceneView.session pause];
        [self.sceneView setSession:nil];
    }
    

    这些销毁方法在视图消失时使用。我也在按下按钮重新启动 AR 会话,但不是通过这些方法。如下:

    -(void)resetPressed{
        NSLog(@"Reset Pressed");
        [_sceneView.session pause];
    
    
        SCNScene *scene = [[SCNScene alloc] init];
        [_sceneView setScene:scene];
        [_sceneView.scene.rootNode enumerateChildNodesUsingBlock:^(SCNNode * _Nonnull child, BOOL * _Nonnull stop) {
            [child removeFromParentNode];
        }];
    
        ARWorldTrackingConfiguration *configuration = [[ARWorldTrackingSessionConfiguration ARWorldTrackingConfiguration] init];
        [_sceneView.session runWithConfiguration:configuration options:ARSessionRunOptionResetTracking | ARSessionRunOptionRemoveExistingAnchors];
    }
    

    希望对你有帮助。

    【讨论】:

    • 这是我一直在做的。但是,如果长时间丢失帧,则会以某种方式创建 ARSession 的第二次。相机状态无限期保持在 ARTrackingStateLimited。
    • 我不太明白你是如何解决世界中心坐标的变化的。第二次运行会话时,世界很可能不会处于同一个中心。所以所有加载的节点都会错位。你能给我一个解决这个问题的方法吗,因为我能想到的只是一些 ImageRecognition 软件,它可以以某种方式翻译世界中心的变化,并从那里给出一个翻译矩阵。有更好的建议吗?
    • @dvp.petrov 我没有解决坐标的变化。我只是在解决问题中的问题,即当 OP 返回 AR 视图控制器时,AR 会话被暂停并且不会移动。我只是提供了一种在您返回该视图控制器后重新启动会话的方法。关于您的问题,我想您可以保存已添加的所有节点的位置,并在您回来后重新添加它们,但不能保证该设备届时将位于同一物理位置.
    • @AlanS - 我很好奇您第二次运行 ARSession 是否和第一次一样稳定?在我的第二次运行中,我将它永远作为 ARTrackingStateReasonInitializing 并且它永远不会变成 ARTrackingStateReasonNone。
    • 我在第三次重新访问 ARView 控制器时遇到了同样的问题。我离开视图时调用sceneView.session.pause(),返回时调用.run。我从不放松视图。我只是继续使用相机视图来捕捉照片。这可能是问题吗?
    【解决方案3】:

    我不知道 iOS 11 GM Seed 或 XCode 9 GM Seed 版本今天是否修复了这个问题,但是我可以使用原始问题中的代码成功恢复暂停的 ARSCNview。

    sceneView.session.run(sceneView.session.configuration!)
    

    【讨论】:

    • 接受的答案还说他们无法重现该问题并进行了更详细的说明。是否可以编辑此答案以增加 OP 和其他有此问题的人的价值?
    • 这对我很有用!首先 self.sceneView.session.pause() 然后是 sceneView.session.run(sceneView.session.configuration!)
    【解决方案4】:

    这是一个适用于 Swift 4.2 和 iOS 12 的答案。

    要在您的 AR 场景中呈现在另一个视图控制器中定义的 UI,请创建您的视图控制器实例并将其 modalPresentationStyle 属性设置为 .overCurrentContext

    EXAMPLE:
    
    func showMaterialPicker(completion: (Texture?) -> Void) {
    
        // create an instance of your view controller, I have convenience functions
        // setup to do this via an extension on UIViewController
        guard let materialPicker = MaterialCategoriesViewController.instance(from: .product) else {
            print("Unable to instantiate MaterialCategoriesViewController, bailing")
            return
        }
    
        // set presentation style and transition style
        materialPicker.modalPresentationStyle = .overCurrentContext
        materialPicker.modalTransitionStyle = .crossDissolve
    
        // present the controller
        present(materialPicker, animated: true, completion: nil)
    }
    

    额外提示:

    要使您的叠加层看起来像抽屉一样从底部向上滑动,请设置

    materialPicker.modalTransitionStyle = .coverVertical
    

    然后将覆盖视图控制器中的视图限制在距底部舒适的高度,并将视图控制器视图的背景颜色设置为 UIColor.clear。

    如果您想在显示叠加层时使 AR 视图变暗,您可以将背景颜色设置为黑色,不透明度/alpha 值约为 0.75。

    类似这样的:

    self.view.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.75)
    

    或在故事板中:

    在上面的屏幕截图中,我有一个固定在覆盖视图控制器视图底部和侧面的表格视图,高度限制为 300。

    这样做后,您仍然可以看到覆盖视图控制器后面的 AR 视图,并且场景继续渲染。

    【讨论】:

    • 终于!两天后,我可以说它做到了!我实际上遇到了一些不同的问题。当我在 SceneViewController 上展示 NewViewController 时,NewViewController 冻结了。我尝试暂停、恢复会话、完全删除场景并在 viewWillAppear 上重新初始化 - 没有任何效果。只有我遇到了@digitalHound 的这篇文章并使用了 newViewController.modalPresentationStyle = .overCurrentContext 我能够解决这个问题!再次感谢@digitalHound
    • @kalafun:大家好。我也面临同样的问题。当我将新视图控制器推到 sceneViewController 顶部时,它会完全冻结。我尝试用上面的建议提出它,但仍然不起作用。你还有什么推荐的吗?
    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    相关资源
    最近更新 更多