iOS Development

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

Spread the love


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

  • App opens to a .nonAR ARView FirstARView
  • This can present a crimson background with a blue field exhibiting a single facet of the field face on
  • There shall be some crimson 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()

Be aware on why you need 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 via you see the .nonAR ARView FirstARView disappearing, and even via 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 difficulty. Does anybody perceive the inc.navigationDestination and ARKit session and why that is the case? Be aware you clearly don’t even have to pause() and alter the digital camera 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?.atmosphere.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(.crimson)
                }
            }
            .navigationDestination(isPresented: $loadSecondView) {
                MagicARView()
            }
        }
    }
}

struct MagicARView: UIViewRepresentable {

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

        let boxMesh = MeshResource.generateBox(measurement: 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.atmosphere.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(measurement: 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.atmosphere.background = .colour(.crimson)
        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(.crimson)
                }
            }
            
        }
    }
}

struct MagicARView: UIViewRepresentable {

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

        let boxMesh = MeshResource.generateBox(measurement: 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.atmosphere.sceneUnderstanding.choices.insert(.occlusion)

        let boxMesh = MeshResource.generateBox(measurement: 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.atmosphere.background = .colour(.crimson)
        firstViewController!.arView = arView
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
}

One thought on “swift – iOS: NavigationStack.navigationDestination breaks ARKit Session utilized in RealityKit ARView

  1. certainly like your website but you need to take a look at the spelling on quite a few of your posts Many of them are rife with spelling problems and I find it very troublesome to inform the reality nevertheless I will definitely come back again

Leave a Reply

Your email address will not be published. Required fields are marked *