How to clear the background of a SceneView 3D Object in SwiftUI

799 Views Asked by At

Does anyone knows how to clear the background of a SceneView 3D Object? I'm trying using UIColor.clear, but it makes it white. [This should be clear, but it's white]

import SwiftUI
import SceneKit

struct TestView: View {
    var body: some View {
    
        ZStack{
                    Color.green
                    SceneView(
                        scene: {
                            let scene = SCNScene(named: "Earth.scn")!
                            scene.background.contents = UIColor.clear
                            return scene
                        }(),
                        options: [.autoenablesDefaultLighting,.allowsCameraControl]
                    )
                    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/2, alignment: .center)
                
                }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}
2

There are 2 best solutions below

0
On

Here's a solution that worked for me, mostly adopted from the answers here:

import SceneKit
import SwiftUI

final class EarthSceneView: UIViewRepresentable {
    typealias UIViewType = SCNView
    typealias Context = UIViewRepresentableContext<EarthSceneView>

    func updateUIView(_ uiView: UIViewType, context: Context) {}
    func makeUIView(context: Context) -> UIViewType {
        let view = SCNView()
        view.backgroundColor = UIColor.clear // this is key!
        view.allowsCameraControl = true
        view.autoenablesDefaultLighting = true
        // load the scene here, could load an .obj file too
        view.scene = SCNScene(named: "Earth.scn")!
        return view
    }
}

Then you can use it in your view as:

import SwiftUI

struct TestView: View {
    var body: some View { 
        ZStack{
            Color.green
            EarthSceneView()
                .frame( // set frame as required
                    maxWidth: .infinity,
                    maxHeight: .infinity,
                    alignment: .center
                )
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}
0
On

I know that I'm late, but here is a refined approach described in the other answers:

struct TestView: View {
    var body: some View {
        ZStack {
            Color.green
            LegacySceneView(scene: {
                    let scene = SCNScene()
                    scene.background.contents = UIColor.clear
                    return scene
                }(), options: [.autoenablesDefaultLighting,.allowsCameraControl]
            )
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/2, alignment: .center)
        }
    }
}

struct LegacySceneView: UIViewRepresentable {
    var scene: SCNScene
    var options: SceneView.Options
    
    func makeUIView(context: Context) -> SCNView {
        let view = SCNView()
        view.backgroundColor = UIColor.clear
        view.allowsCameraControl = options.contains(.allowsCameraControl)
        view.autoenablesDefaultLighting = options.contains(.autoenablesDefaultLighting)
        view.rendersContinuously = options.contains(.rendersContinuously)
        view.isJitteringEnabled = options.contains(.jitteringEnabled)
        view.isTemporalAntialiasingEnabled = options.contains(.temporalAntialiasingEnabled)
        view.scene = scene
        return view
    }
    
    func updateUIView(_ uiView: SCNView, context: Context) { }
}

You just need to replace the SceneView to LegacySceneView. No other changes are required. Enjoy!