ARKit会话已暂停且未恢复

时间:2017-07-07 21:02:05

标签: ios arkit

在我的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 个答案:

答案 0 :(得分:7)

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

请注意附带Apple的ARKit示例代码(附于WWDC17 session on ARKit)的自述文件:

  

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

     

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

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

答案 1 :(得分:3)

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

int realizar_reparaciones(int naves_a_reparar, int repuestos_laser, int repuestos_escudos, int repuestos_compensadores){
int caracter_valido = 0;
char reparacion_necesaria;
int naves_con_alambre = 0;
int contador_laser = 0;
int contador_escudo = 0;
printf ("A continuación deberá ingresar uno de los siguientes valores por nave: L (Generador Láser) o E (Generador de escudo deflector)\n");
for (int i = 1; i <= naves_a_reparar; i = i + 1){
    while (caracter_valido == 0){
        printf ("Ingrese la reparación que hay que realizarle a la nave %d: ", i);
        scanf (" %c", &reparacion_necesaria);
        switch (reparacion_necesaria){
            case 'L': 
                if (repuestos_laser == 0){
                    naves_con_alambre = naves_con_alambre + 1;
                } else {
                    repuestos_laser = repuestos_laser - 1;
                    contador_laser = contador_laser + 1;
                }
                caracter_valido = 1;
            break;
            case 'E': 
                if (repuestos_escudos == 0){
                    naves_con_alambre = naves_con_alambre + 1;
                } else {
                    repuestos_escudos = repuestos_escudos - 1;
                    contador_escudo = contador_escudo + 1;
                }
                caracter_valido = 1;
            break;
            default: 
                printf ("Ingrese unicamente alguno de los caracteres previamente mencionados\n");
            break;
        }
    }
}
printf ("Se utilizaron %d generadores láser\n", contador_laser);
printf ("Se utilizaron %d generadores de escudos deflectores\n", contador_escudo);
printf ("Se utilizaron %d compensadores de aceleracion\n", contador_compensador);
return naves_con_alambre;

答案 2 :(得分:2)

我知道你选择了一个答案,答案是apple推荐的,你可以重启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];
}

视图消失时使用这些destroy方法。我也在按下按钮时重新启动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];
}

希望它有所帮助。

答案 3 :(得分: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)

或在故事板中:

enter image description here

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

以这种方式完成操作后,您仍然可以在叠加视图控制器后面看到AR视图,并且场景将继续渲染。