ratamaster
ratamaster

Reputation: 169

SCNNode is not showing up

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 !

Upvotes: 1

Views: 723

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58553

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.

Upvotes: 2

Related Questions