Search code examples
iosswiftswiftuiscenekitscnscene

SwiftUI – Setting SceneView background to video


I'm trying to set the SceneViews background to a .mov video. I can get the video to play if I pass it to a VideoPlayer but not if I set it as a material on my Sphere & use it in my SceneView. Ideally I would like the video to play behind the sphere but I would settle for applying it as a material. I have looked at this solution but it hasn't worked, I just see white.

Any help getting a video in my Scene is much appreciated!!

View:

GeometryReader { _ in
  SceneView(scene: testScene, options: [.allowsCameraControl])
}

Scene Creation:

private var testScene: SCNScene? {
  var earthScene = SCNScene()

  let material = SCNMaterial()
  let path = Bundle.main.url(forResource: "test_video", 
                                 withExtension: "mov")!
  let player = AVPlayer(url: path)
  player.play()
  material.diffuse.contents = player

  let earthNode = SCNNode()
  earthNode.geometry = SCNSphere(radius: CGFloat(150))
  earthScene.rootNode.addChildNode(earthNode)
  earthNode.geometry?.materials = [material]

  earthScene.rootNode.addChildNode(earthNode)
  return flowerScene
}

Solution

  • This code works perfectly in Xcode 14.2 (target is iOS 16.2).

    import SwiftUI
    import SceneKit
    import AVFoundation
    
    struct ContentView: View {
        var body: some View {
            SceneKitter().ignoresSafeArea()
        }
    }
    

    struct SceneKitter : UIViewRepresentable {
        
        func makeUIView(context: Context) -> SCNView {
            let sceneView = SCNView(frame: .zero)
            sceneView.scene = sceneMethod()
            sceneView.isPlaying = true                 // solves the problem
            sceneView.allowsCameraControl = true
            return sceneView
        }
        
        func sceneMethod() -> SCNScene {
            let scene = SCNScene()
            scene.background.contents = UIColor.black
            
            let path = Bundle.main.url(forResource: "video",
                                     withExtension: "mp4")!
            let player = AVPlayer(url: path)
            player.play()
    
            let material = SCNMaterial()
            material.diffuse.contents = player
    
            let earthNode = SCNNode()
            earthNode.geometry = SCNSphere(radius: 1)
            earthNode.geometry?.materials[0] = material
            scene.rootNode.addChildNode(earthNode)
            return scene
        }
        
        func updateUIView(_ view: SCNView, context: Context) { }
    }