SCNNode is not showing up

Viewed 346

I'm new in Swift and ARKit. For some reason the SCNNode node I'm trying to display is not showing up. I'm working with SwiftUI. I defined in the next code block the function addNode that should render the node.

import Foundation
import ARKit
import SwiftUI

// MARK: - ARViewIndicator
struct ARViewIndicator: UIViewControllerRepresentable {
   typealias UIViewControllerType = ARView
   
   func makeUIViewController(context: Context) -> ARView {
      return ARView()
   }
   func updateUIViewController(_ uiViewController:
   ARViewIndicator.UIViewControllerType, context:
   UIViewControllerRepresentableContext<ARViewIndicator>) { }
}


class ARView: UIViewController, ARSCNViewDelegate {
    var arView: ARSCNView {
        return self.view as! ARSCNView
    }
    
    override func loadView() {
     self.view = ARSCNView(frame: .zero)
    }
    
    override func viewDidLoad() {
      super.viewDidLoad()
      arView.delegate = self
      arView.scene = SCNScene()
    }

    // MARK: - Functions for standard AR view handling
   override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(animated)
   }
    
   override func viewDidLayoutSubviews() {
      super.viewDidLayoutSubviews()
   }
    
   override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let configuration = ARWorldTrackingConfiguration()
        arView.debugOptions = [.showFeaturePoints, 
                               .showWorldOrigin]
        arView.session.run(configuration)
        arView.delegate = self
   }
    
   override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      arView.session.pause()
   }
    
    func addNode(){
        let node = SCNNode()
        node.geometry = SCNBox(width: 0.1, 
                              height: 0.1, 
                              length: 0.1, 
                       chamferRadius: 0)
        node.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
        node.position = SCNVector3(0,0,0.3)
        arView.scene.rootNode.addChildNode(node)
        arView.delegate = self
        
        print(123)
    }
    
   // MARK: - ARSCNViewDelegate
   func sessionWasInterrupted(_ session: ARSession) {}
   
   func sessionInterruptionEnded(_ session: ARSession) {}
   func session(_ session: ARSession, didFailWithError error: Error)
   {}
   func session(_ session: ARSession, cameraDidChangeTrackingState
   camera: ARCamera) {}
    
}

... and that function is invoked when clicking the button "HOME"

import SwiftUI
import ARKit

// MARK: - NavigationIndicator
struct NavigationIndicator: UIViewControllerRepresentable {
   typealias UIViewControllerType = ARView
   func makeUIViewController(context: Context) -> ARView {
      return ARView()
   }
   func updateUIViewController(_ uiViewController:
   NavigationIndicator.UIViewControllerType, context:
   UIViewControllerRepresentableContext<NavigationIndicator>) { }
}

struct ContentView: View {
   @State var page = "Home"
   
   var body: some View {
      VStack {
        ZStack {
           NavigationIndicator()
            VStack {
                Spacer()
                HStack {
                    Button("Home") {
                        let ar = ARView();
                        ar.addNode()                        
                    }.padding()
                     .background(RoundedRectangle(cornerRadius: 10)
                     .foregroundColor(Color.white).opacity(0.7))
                    Spacer()
               }
          }
        }
      }
   }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Do you know why it's not showing up ? Thanks in advance !

1 Answers

Use this approach for SceneKitView:

import SwiftUI
import ARKit

struct SceneKitView: UIViewRepresentable {
    
    let arView = ARSCNView(frame: .zero)
    @Binding var pressed: Bool
    @Binding var node: SCNNode
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    final class Coordinator: NSObject, ARSCNViewDelegate {
        
        var control: SceneKitView
        
        init(_ control: SceneKitView) {
            self.control = control
        }
        
        func renderer(_ renderer: SCNSceneRenderer,
               updateAtTime time: TimeInterval) {
            
            if control.pressed {
                self.control.node = self.addCube()
                self.control.arView.scene.rootNode.addChildNode(control.node)
            }
        }
        
        fileprivate func addCube() -> SCNNode {
            control.node.geometry = SCNBox(width: 0.25,
                                          height: 0.25,
                                          length: 0.25,
                                   chamferRadius: 0.01)
            control.node.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
            control.node.geometry?.firstMaterial?.lightingModel = .phong
            control.node.position = SCNVector3(0, 0,-2)
            return control.node
        }
    }
        
    func makeUIView(context: Context) -> ARSCNView {
        arView.scene = SCNScene()
        arView.delegate = context.coordinator
        arView.autoenablesDefaultLighting = true
        arView.debugOptions = .showFeaturePoints
        // arView.allowsCameraControl = true
        
        let config = ARWorldTrackingConfiguration()
        arView.session.run(config)
        
        return arView
    }
    
    func updateUIView(_ uiView: ARSCNView,
                       context: Context) { }
}

Then use this code for ContentView.

struct ContentView: View {
    
    @State var pressed: Bool = false
    @State var node = SCNNode()
       
    var body: some View {
        ZStack {
            SceneKitView(pressed: $pressed, node: $node)
            VStack {
                Spacer()
                HStack {
                    Button("Blue Cube") {
                        pressed.toggle()
                    }.padding()
                     .foregroundColor(.red)

                    Spacer()
                }
            }
        }
    }
}

enter image description here

P.S.

However, a strange issue occurs with ARSCNView in Simulator – after pressing a button a SCNBox appears only after tapping a screen with .allowsCameraControl = true.

Related