ARKit/SceneKit Shadow Issue

Viewed 314

I'm working on an ARKit app for iPhone and iPad and I'm having some troubles getting the shadows to work in the live view from the camera. My scene (ShadowTest.scn) looks like the following:

Scene Graph

I have unchecked Red, Green, Blue, and Alpha for the Write to Color property on the material for the plane as well as set the visibility to Cull back.

For the directional light, Enable Shadows is selected and the mode is set to Deferred.

In the scene file itself, everything looks good. The shadow is visible and the plane is not.

My issue is when I go to add it to my scene view. This is how I'm adding it to my scene:

func addTestBox(at position: SCNVector3, rotation: SCNVector4) {
    guard let scene = SCNScene(named: "Assets.scnassets/ShadowTest.scn") else {
        return
    }

    let node = SCNNode()

    scene.rootNode.childNodes.forEach(node.addChildNode(_:))

    node.position = position
    node.rotation = rotation

    updateQueue.async { [weak self] in
        self?.sceneView.scene.rootNode.addChildNode(node)
    }
}

When the nodes are added to my scene, the shadow is not visible at all.

AR View with no Shadow

The lighting appears to be working because it is lit as it should be.

Am I missing some very obvious setting on the light/plane/cube/scene view that is needed to make the shadows show up?

Thank you in advanced for all the help.

1 Answers

You should be able to do this in code. Try this for the light:

func directionalLight() -> SCNLight {
    
    let light                           = SCNLight()
    light.type                          = .directional
    light.castsShadow                   = true
    light.color                         = UIColor.white
    light.shadowColor                   = UIColor(red: 0, green: 0, blue: 0, alpha: 0.75)
    light.shadowMode                    = .deferred
    light.shadowRadius                  = 2.0
    light.shadowCascadeCount            = 3
    light.shadowCascadeSplittingFactor  = 0.09
    light.shadowBias                    = 0.1
    light.shadowSampleCount             = 8 // (the smaller the value, the better the performance)
    light.categoryBitMask               = -1 // Shine on Everything

    return light
    
}

and this for the Material:

func shadowMaterialStandard() -> SCNMaterial {
    
    let material = SCNMaterial()
    
    
    material.diffuse.contents       = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
    material.lightingModel          = .physicallyBased
    material.colorBufferWriteMask   = SCNColorMask(rawValue: 0)
    material.isLitPerPixel          = false
    material.isDoubleSided          = true
    
    
    return material
}

and this for the SCNPlane (the Shadow Plane):

func setupShadowPlane() {
    
    let objectShape = SCNPlane(width: 50.0, height: 50.0)
    objectShape.heightSegmentCount = 1
    objectShape.widthSegmentCount = 1
    
    let objectNode = SCNNode(geometry: objectShape)
    objectNode.renderingOrder = -10 // for Shadow Material Standard
    objectNode.position = initialStartPosition
    objectNode.geometry?.firstMaterial = shadowMaterialStandard()
    objectNode.castsShadow = false // Important
    objectNode.eulerAngles = SCNVector3(-90.degreesToRadians, 0.0, 0.0)
    objectNode.name = "floor"
    objectNode.physicsBody = Physics.floorPhysicsBody(shape: objectShape)
    
    sceneView.scene.rootNode.addChildNode(objectNode)
    
}
Related