Dans mon application ARKit, je présente une fenêtre modale. Lorsque je ferme le modal et que je retourne à ARSCNView, je découvre que la session est suspendue à cause de ce code:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
Lorsque je ferme le modal et que je reviens à l'écran de vue de la caméra ARKit, ce code est déclenché:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingSessionConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
Mais ce code ne reprend jamais la session. L'écran est complètement figé sur la dernière image lue. Des idées?
Je mets à jour le code viewDidAppear pour être le suivant. Il est toujours bloqué sur l'écran de l'appareil photo avec l'image figée.
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)
}
}
Vous ne savez pas pourquoi votre session ne reprend pas, mais ... ce n'est généralement pas une situation dans laquelle vous voulez être.
Notez dans le fichier Lisez-moi fourni avec le code exemple ARKit d’Apple (joint à la session WWDC17 sur ARKit ):
Evite d'interrompre l'expérience AR. Si l'utilisateur effectue la transition vers une autre interface utilisateur plein écran dans votre application, la vue AR risque de ne pas être un état attendu à son retour.
Utilisez la présentation popover (même sur iPhone) pour les contrôleurs de vue auxiliaires afin de permettre à l'utilisateur de rester dans l'expérience AR lors du réglage des paramètres ou de la sélection modale. Dans cet exemple, les classes
SettingsViewController
etVirtualObjectSelectionViewController
utilisent la présentation popover.
Pour entrer un peu plus dans les détails: si vous mettez la session en pause, il ne suivra pas le monde pendant que votre utilisateur est absent dans un autre contrôleur d'affichage en plein écran. Cela signifie que lors de la reprise, aucun contenu virtuel placé dans la scène ne sera dans les positions (par rapport à la caméra) où vous l'avez laissé.
Je ne sais pas si les versions iOS 11 GM Seed ou XCode 9 GM Seed ont été corrigées aujourd'hui, mais je peux reprendre avec succès une ARSCNview suspendu avec le code comme dans la question initiale.
sceneView.session.run(sceneView.session.configuration!)
Je comprends que vous avez choisi une réponse, et que cette réponse est celle recommandée par Apple, vous pouvez redémarrer la session AR. Cependant, vous ne pouvez pas suspendre/reprendre la session, car le périphérique arrête le suivi une fois que vous êtes sorti de votre contrôleur et ne présentez pas ARSceneView et il ne gardera plus la trace de la position de votre périphérique par rapport aux objets que vous avez placés dans la scène. .
Quoi qu'il en soit, j'ai réussi à redémarrer la session essentiellement en détruisant tous les aspects de ma session et en les reconstruisant lorsque mon point de vue réapparaît ou par le biais d'une pression sur un bouton.
Je vais poster un exemple de code ici. C'est en Objective-C parce que mon projet a été écrit en cela, mais il pourrait aider les futurs gens avec la même question.
-(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];
}
Ces méthodes de destruction sont utilisées lorsque la vue disparaît. Je suis également en train de redémarrer la session AR sur une touche, mais ce n'est pas par ces méthodes. C'est comme suit:
-(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];
}
J'espère que ça aide.
Voici une réponse qui fonctionne avec Swift 4.2 et iOS 12.
Pour présenter l'interface utilisateur définie dans un autre contrôleur de vue sur votre scène AR, créez votre instance de contrôleur de vue et définissez sa propriété modalPresentationStyle
sur .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)
}
Bonus:
Pour que votre superposition semble glisser vers le haut, comme un tiroir, définissez
materialPicker.modalTransitionStyle = .coverVertical
contraignez ensuite vos vues dans votre contrôleur de vue en superposition à une hauteur confortable par rapport au bas et définissez la couleur d'arrière-plan de la vue des contrôleurs de vue sur UIColor.clear.
Si vous souhaitez assombrir la vue RA lorsque la superposition est affichée, vous pouvez définir la couleur d'arrière-plan sur une couleur noire avec une valeur d'opacité/alpha d'environ 0,75.
Quelque chose comme ça:
self.view.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.75)
ou dans le storyboard:
Dans la capture d'écran ci-dessus, j'ai une vue de table épinglée au bas et aux côtés de la vue des contrôleurs de vue de superposition, ainsi qu'une contrainte de hauteur de 300.
Lorsque vous avez terminé, vous pouvez toujours voir la vue AR derrière le contrôleur de superposition et la scène continue à être rendue.