SceneKit display a USDZ object on the screen with SwiftUI

381 Views Asked by At

I have created a carousel with a ScrollView that contains as many buttons as there are .usdz files. In the ResourceButton structure, when you tap on a button, it should:

Check if a .usdz file is already present. If yes: -Remove the old one. -Add the new one. Otherwise: -Add the new .usdz file to the scene.

My logic seems correct, and there are no error messages. However, when I tap on a button on the device, nothing appears on the screen. Can anyone see what my error might be? Thank you in advance

import scenekit
import swiftui

struct ContentView: View {
    @State private var isUSDZDisplayed = false
    @State private var sceneKitView = SceneKitView(isUSDZDisplayed: .constant(false)) // Create SceneKitView's instance
    
    var body: some View {

            VStack(alignment: .bottom) {
            SceneKitView(isUSDZDisplayed: $isUSDZDisplayed)
                .frame(height: 300)
            Spacer()
            // Overlay aand buttons
            ScrollView(.horizontal, showsIndicators: false) {
                HStack {
                    ForEach(0..<resourceFiles.count, id: \.self) { index in
                        ResourceButton(fileName: resourceFiles[index], isUSDZDisplayed:    $isUSDZDisplayed, sceneKitView: sceneKitView)
                    }
                }
                .padding()
                .padding(.bottom, 1)
            }
        }
    }
}

struct SceneKitView: UIViewRepresentable {
    
    @Binding var isUSDZDisplayed: Bool
       private let sceneView = SCNView()
       
       init(isUSDZDisplayed: Binding<Bool>) {
           self._isUSDZDisplayed = isUSDZDisplayed
       }

    func makeUIView(context: Context) -> SCNView {
        let scnView = SCNView()
        let scene = SCNScene()
            if let url = Bundle.main.url(forResource: "digestiveS", withExtension: "usdz") {
                 let scene = try! SCNScene(url: url, options: nil)
            let scaleFactor: CGFloat = 0.5
        }
                // ... (Create and position your model SCNNode here)
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light?.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)
        scene.rootNode.scale = SCNVector3(0.5, 0.5, 0.5)

        scnView.scene = scene
        scnView.autoenablesDefaultLighting = true
        scnView.allowsCameraControl = true
        return scnView
    }

    func updateUIView(_ uiView: SCNView, context: Context) 
    {
        // update if needed
    }
    
    func addUSDZObject(fileName: String)
    {
        if let scene = loadScene(fileName: fileName) 
        {
            sceneView.scene = scene
            isUSDZDisplayed = true
        }
    }
    
    func removeUSDZObject() 
    {
        sceneView.scene = nil
        isUSDZDisplayed = false
    }
    
    private func loadUSDZScene(named modelName: String) -> SCNNode? 
    {
            guard let usdzURL = Bundle.main.url(forResource: modelName, withExtension: "usdz") else 
            {
            return nil
            }
            let referenceNode = SCNReferenceNode(url: usdzURL)
            referenceNode?.load()
            return referenceNode
    }
    
    
    private func loadScene(fileName: String) -> SCNScene? 
    {
        if let modelURL = Bundle.main.url(forResource: fileName, withExtension: "usdz") 
        {
            let scene = try? SCNScene(url: modelURL, options: nil)
            print("DEBUG: button name: \(String(describing: scene))")
            return scene
        }
        return nil
    }
}

struct ResourceButton: View {
    let fileName: String
    @Binding var isUSDZDisplayed: Bool
    let sceneKitView: SceneKitView

     init(fileName: String, isUSDZDisplayed: Binding<Bool>, sceneKitView: SceneKitView) {
         self.fileName = fileName
         self._isUSDZDisplayed = isUSDZDisplayed
         self.sceneKitView = sceneKitView
     }

    var body: some View {
        Button(action: {

            if isUSDZDisplayed {
                           // remove USDZ from screen
                sceneKitView.removeUSDZObject()
                 // add new USDZ from screen
                sceneKitView.addUSDZObject(fileName: fileName)
                       } else {

                           // add new USDZ from screen
                           sceneKitView.addUSDZObject(fileName: fileName)
                       }
                       // switch USDZ dispalyed state
                       isUSDZDisplayed.toggle()

        }) {
            Image(uiImage: UIImage(named: fileName) ?? UIImage()) // load picture  from filename 
                            .resizable()
                            .frame(width: 40, height: 40) 
                            .padding(2.5)
                            //.background(Color.blue)
                            .aspectRatio(1/1, contentMode: .fit)
                            .cornerRadius(12)
                            .foregroundColor(.white)
        }
        .buttonStyle(PlainButtonStyle())
        .padding(.trailing, 10)
        .background(Color.black.opacity(0.5))
    }
}

let resourceFiles = ["digestiveS.usdz", "orcas.usdz", "chair_swan.usdz","cup_saucer_set.usdz", "fender_stratocaster.usdz", "flower_tulip.usdz","FruitCakeSlice.usdz", "gramophone.usdz", "LemonMeringuePie.usdz","PegasusTrail.usdz", "robot_walk_idle.usdz", "Rock.usdz","slide.usdz", "solar_panels.usdz", "teapot.usdz","toy_biplane_idle.usdz", "toy_car.usdz", "toy_drummer_idle.usdz","tv_retro.usdz", "wateringcan.usdz", "AirForce.usdz"]  // usdz fileName

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

There are 0 best solutions below