11

在我的 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)
        }


    }
4

4 回答 4

11

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

请注意 Apple 的 ARKit 示例代码附带的自述文件(附加到ARKit 上的 WWDC17 会话):

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

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

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

于 2017-07-07T22:14:55.927 回答
5

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

sceneView.session.run(sceneView.session.configuration!)
于 2017-09-13T03:09:58.820 回答
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];
}

希望能帮助到你。

于 2017-08-10T09:01:15.070 回答
1

这是使用 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 视图,并且场景继续渲染。

于 2018-12-01T01:04:22.737 回答