10.7 C
London
Thursday, February 1, 2024

swift – iOS: NavigationStack.navigationDestination breaks ARKit Session utilized in RealityKit ARView


The next code is described as doing (that is associated to Actuality Equipment ARView, though I’m accessing the underlying ARKit Session as you will notice):

  • App opens to a .nonAR ARView FirstARView
  • It will present a purple background with a blue field displaying a single facet of the field face on
  • There will likely be some purple textual content which says Press the button, while you press this the app makes use of a NavigationStack.navigationDestination to open a second RealityKit ARView MagicARView

Earlier than the MagicARView opens the next happens to the ARKit session from .nonAR ARView FirstARView

  1. Pause
  2. Change digicam mode to .AR
  3. Change the background to be .CameraFeed()
  4. Run()
  5. Pause()

Be aware on why you must do the above steps 1 to five:
I had a earlier subject when switching between a view with a .nonAR view and an .AR view the place the digicam feed on the .AR view was simply black – the one approach to overcome this appears to be working the above steps on the underlying ARKit session earlier than switching to the second .AR view.

Now when the second .AR MagicARView opens there will likely be a big blue field which seems at [0,0,0].

Anticipated behaviour: you’ll be able to transfer across the room (eg: transfer behind a partial wall) and the field will likely be occluded by the wall.

Precise behaviour: you’ll be able to transfer across the room (eg: transfer behind a partial wall) and the field IS NOT occluded by the wall – occlusion is damaged.

My assumption: Even by means of you see the .nonAR ARView FirstARView disappearing, and even by means of I’m going to nice lengths to set each the arView within the FirstController and even the FirstController itself to nil – one thing is being held onto incorrectly within the underlying ARKit Session (apparently there is just one per app…)

My resolution and query: See the second code block for the answer – for those who take away the .navigationDestination and use conditionals within the ContentView it seems to resolve the problem. Does anybody perceive the inc.navigationDestination and ARKit session and why that is the case? Be aware you clearly don’t even must pause() and alter the digicam when doing it this manner.

import SwiftUI
import RealityKit
import ARKit

let configuration: ARWorldTrackingConfiguration = {
    let config = ARWorldTrackingConfiguration()
    
    if (ARWorldTrackingConfiguration.supportsSceneReconstruction(ARWorldTrackingConfiguration.SceneReconstruction.mesh)) {
        config.sceneReconstruction = .mesh
    }
    
    config.planeDetection = [.vertical, .horizontal]
    
    return config
}()

class FirstViewController {
    weak var arView: ARView?
}

class FirstViewControllerWrapper {
    var firstController: FirstViewController?
    
    init() {
        firstController = FirstViewController()
    }
}

struct ContentView: View {
    @State var loadSecondView: Bool = false
    
    var firstViewControllerWrapper: FirstViewControllerWrapper?
    
    init () {
        firstViewControllerWrapper = FirstViewControllerWrapper()
    }
    
    var physique: some View {
        NavigationStack{
            ZStack{
                FirstARView(firstViewController: firstViewControllerWrapper!.firstController!)
                    .onDisappear(){
                        print("First view is disappearing")
                    }
                Button(motion: {
                    firstViewControllerWrapper?.firstController!.arView?.session.pause()
                    firstViewControllerWrapper?.firstController!.arView?.cameraMode = .ar
                    firstViewControllerWrapper?.firstController!.arView?.setting.background = .cameraFeed()
                    firstViewControllerWrapper?.firstController!.arView?.session.run(configuration)
                    firstViewControllerWrapper?.firstController!.arView?.session.pause()
                    firstViewControllerWrapper?.firstController!.arView = nil
                    firstViewControllerWrapper?.firstController = nil
                    loadSecondView = true
                    
                }) {
                    Textual content("Press the button").background(.purple)
                }
            }
            .navigationDestination(isPresented: $loadSecondView) {
                MagicARView()
            }
        }
    }
}

struct MagicARView: UIViewRepresentable {

    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(body: .zero, cameraMode: .ar, automaticallyConfigureSession: true)
        arView.setting.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(colour: .blue, isMetallic: false)
        let mannequin = ModelEntity(mesh: boxMesh, supplies: [boxMaterial])
        let modelAnchor = AnchorEntity(world: [0.2,0.2,0.2])
        modelAnchor.addChild(mannequin)
        arView.scene.addAnchor(modelAnchor)
        arView.session.run(configuration)
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

struct FirstARView: UIViewRepresentable {
    
    weak var firstViewController: FirstViewController?
    
    func makeUIView(context: Context) -> ARView {
    
        let arView = ARView(body: .zero, cameraMode: .nonAR, automaticallyConfigureSession: true)
        arView.setting.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(colour: .blue, isMetallic: false)
        let mannequin = ModelEntity(mesh: boxMesh, supplies: [boxMaterial])
        let modelAnchor = AnchorEntity(world: [0.2,0.2,0.2])
        modelAnchor.addChild(mannequin)
        arView.scene.addAnchor(modelAnchor)
        arView.session.run(configuration)
        arView.setting.background = .colour(.purple)
        firstViewController!.arView = arView
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

Answer?

import SwiftUI
import RealityKit
import ARKit

let configuration: ARWorldTrackingConfiguration = {
    let config = ARWorldTrackingConfiguration()
    
    if (ARWorldTrackingConfiguration.supportsSceneReconstruction(ARWorldTrackingConfiguration.SceneReconstruction.mesh)) {
        config.sceneReconstruction = .mesh
    }
    
    config.planeDetection = [.vertical, .horizontal]
    
    return config
}()

class FirstViewController {
    weak var arView: ARView?
}

class FirstViewControllerWrapper {
    var firstController: FirstViewController?
    
    init() {
        firstController = FirstViewController()
    }
}

struct ContentView: View {
    @State var loadSecondView: Bool = false
    
    var firstViewControllerWrapper: FirstViewControllerWrapper?
    
    init () {
        firstViewControllerWrapper = FirstViewControllerWrapper()
    }
    
    var physique: some View {
        NavigationStack{
            ZStack{
                if (!loadSecondView) {
                    FirstARView(firstViewController: firstViewControllerWrapper!.firstController!)
                        .onDisappear(){
                            print("First view is disappearing")
                        }
                }
                if (loadSecondView){
                    MagicARView()
                }
                Button(motion: {
         
                    loadSecondView = true
                    
                }) {
                    Textual content("Press the button").background(.purple)
                }
            }
            
        }
    }
}

struct MagicARView: UIViewRepresentable {

    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(body: .zero, cameraMode: .ar, automaticallyConfigureSession: true)
        arView.setting.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(colour: .blue, isMetallic: false)
        let mannequin = ModelEntity(mesh: boxMesh, supplies: [boxMaterial])
        let modelAnchor = AnchorEntity(world: [0.2,0.2,0.2])
        modelAnchor.addChild(mannequin)
        arView.scene.addAnchor(modelAnchor)
        arView.session.run(configuration)
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

struct FirstARView: UIViewRepresentable {
    
    weak var firstViewController: FirstViewController?
    
    func makeUIView(context: Context) -> ARView {
    
        let arView = ARView(body: .zero, cameraMode: .nonAR, automaticallyConfigureSession: true)
        arView.setting.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(colour: .blue, isMetallic: false)
        let mannequin = ModelEntity(mesh: boxMesh, supplies: [boxMaterial])
        let modelAnchor = AnchorEntity(world: [0.2,0.2,0.2])
        modelAnchor.addChild(mannequin)
        arView.scene.addAnchor(modelAnchor)
        arView.session.run(configuration)
        arView.setting.background = .colour(.purple)
        firstViewController!.arView = arView
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here