HomeiOS Developmentswift - iOS: NavigationStack.navigationDestination breaks ARKit Session utilized in RealityKit ARView

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 note):

  • App opens to a .nonAR ARView FirstARView
  • This can present a pink background with a blue field displaying a single aspect of the field face on
  • There shall be some pink textual content which says Press the button, if 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 digital camera mode to .AR
  3. Change the background to be .CameraFeed()
  4. Run()
  5. Pause()

Word on why it’s a must to do the above steps 1 to five:
I had a earlier challenge when switching between a view with a .nonAR view and an .AR view the place the digital camera feed on the .AR view was simply black – the one option to overcome this appears to be operating the above steps on the underlying ARKit session earlier than switching to the second .AR view.

Now when the second .AR MagicARView opens there shall 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 shall 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 answer and query: See the second code block for the answer – in the event you 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? Word you clearly don’t even must pause() and alter the digital camera when doing it this fashion.

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?.surroundings.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(.pink)
                }
            }
            .navigationDestination(isPresented: $loadSecondView) {
                MagicARView()
            }
        }
    }
}

struct MagicARView: UIViewRepresentable {

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

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(coloration: .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.surroundings.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(coloration: .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.surroundings.background = .coloration(.pink)
        firstViewController!.arView = arView
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

Resolution?

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(.pink)
                }
            }
            
        }
    }
}

struct MagicARView: UIViewRepresentable {

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

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(coloration: .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.surroundings.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(dimension: 0.5)
        let boxMaterial = SimpleMaterial(coloration: .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.surroundings.background = .coloration(.pink)
        firstViewController!.arView = arView
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments