Search code examples
swiftswiftuiscenekit

How to add multiple SCNScenes to one SCNScene?


I am trying to create an application that will allow to place 3d objects. I was able to write some code that works, but only with geometric objects. I need to add multiple SCNScenes to one scene. How do I implement this?

How I have tried:

let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = .gray
    
let firstScene = SCNScene(named: "Earth.usdz")!
let firstSceneNode = firstScene.rootNode.childNode(withName: "Earth", recursively: true)!
firstSceneNode.rotate(by: .init(0, 0, 0, 0), aroundTarget: SCNVector3(0, -30, 10))
sceneView.scene?.rootNode.addChildNode(firstSceneNode)
    
let secondScene = SCNScene(named: "Venus.usdz")!
let secondSceneNode = secondScene.rootNode.childNode(withName: "Venus", recursively: true)!
sceneView.scene?.rootNode.addChildNode(secondSceneNode)

When I delete secondScene everything works with one model.

Thanks!


Solution

  • In SceneKit each SCNScene can contain multiple SCNNodes connected to scene's root node. As you can see on the image these nodes can be not only geometry but also light fixtures, cameras or particle systems.

    enter image description here

    You can easily retrieve any desirable SCNNode with corresponding materials from any SCNScene tree and paste in into other scene (in this case into empty scene).

    import SwiftUI
    import SceneKit
    
    struct ContentView: View {
        
        var body: some View {
            SceneKitView().ignoresSafeArea()
        }
    }
    
    struct SceneKitView: UIViewRepresentable {
        
        let sceneView = SCNView(frame: .zero)
    
        func makeUIView(context: Context) -> SCNView {
            
            sceneView.allowsCameraControl = true
            sceneView.autoenablesDefaultLighting = true
            sceneView.backgroundColor = .black
            sceneView.scene = SCNScene()
            
            let scene01 = SCNScene(named: "Earth.usdz")!
            let scene02 = SCNScene(named: "Mars.usdz")!
            let scene03 = SCNScene(named: "Sun.usdz")!
    
            let earthNode = scene01.rootNode.childNode(withName: "earthPlanet", 
                                                    recursively: true)!
            earthNode.position.x = -1.0
    
            let marsNode = scene02.rootNode.childNode(withName: "marsPlanet", 
                                                   recursively: true)!
            marsNode.position.x = 0.2
    
            let sunNode = scene03.rootNode.childNode(withName: "sunStar", 
                                                  recursively: true)!
            sunNode.position.x = 1.5
            
            sceneView.scene?.rootNode.addChildNode(earthNode)
            sceneView.scene?.rootNode.addChildNode(marsNode)
            sceneView.scene?.rootNode.addChildNode(sunNode)
            return sceneView
        }
        func updateUIView(_ uiView: SCNView, context: Context) { }
    }
    

    P.S.

    But you can't load multiple SCNScenes into single SCNScene.