Search code examples
swiftscenekitarkit

How to make a transparent object that casts a shadow in SceneKit?


I need to make a transparent object in SceneKit that casts a shadow. I tried going through all the texture settings, but I didn't get a positive result. If you completely hide the textures of the object, the shadow disappears.

I need to get a shadow without displaying an object and I don't understand how to do it.


Solution

  • Shadow catcher

    To make an invisible object that casts a shadow in SceneKit, use .shadowOnly lighting model.

    import SceneKit
    import Cocoa
    
    class ViewController: NSViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let sceneView = self.view as! SCNView
            sceneView.scene = SCNScene()
            sceneView.backgroundColor = .darkGray
            sceneView.allowsCameraControl = true
            
            let lightNode = SCNNode()
            lightNode.light = SCNLight()
            lightNode.light?.type = .directional
            lightNode.light?.castsShadow = true
            lightNode.eulerAngles.x = -.pi/4
            sceneView.scene?.rootNode.addChildNode(lightNode)
            
            let sphere = SCNNode(geometry: SCNSphere(radius: 2))
            sphere.geometry?.firstMaterial?.lightingModel = .shadowOnly    // 1
            sphere.geometry?.firstMaterial?.colorBufferWriteMask = []      // 2
            sphere.geometry?.firstMaterial?.transparencyMode = .rgbZero    // 3
            sceneView.scene?.rootNode.addChildNode(sphere)
            
            let plane = SCNNode(geometry: SCNPlane(width: 10, height: 10))
            plane.position.y = -2
            plane.eulerAngles.x = -.pi/2
            sceneView.scene?.rootNode.addChildNode(plane)
        }
    }
    

    enter image description here

    If you need just a shadow catcher (i.e. transparent plane) add the following line to your code:

    plane.geometry?.firstMaterial?.lightingModel = .shadowOnly
    

    To control shadow's transparency use this property:

    lightNode.light?.shadowColor = NSColor(white: 0, alpha: 0.5)
    

    enter image description here