2
votes

I'm working on an ARKit project in swift.

In SWIFT I add objects to the scene. What I want to do with those objects is show a shadow beneath them to make them more realistic. I tried some things and those all didn't work. I'll explain that here.

Please understand that I'm still new to swift. I'm creating objects programmatically in SWIFT. I thought I could do it by creating a invisible plane underneath all the objects and place a light above the scene. I learned that I can cast a shadow on an invisible plane in the Scene editor from Xcode by unchecking the "write to color" values red, green, blue and alpha. I placed a spot light above it and it worked. Now I want to do this programatically.

In swift I created the light's and the plane as shown below. I don't use a spot anymore because the scene is so large. That's why I create a really large plane. I added those to light's ambient and directional. Ambient so it doesn't look black on the side and directional so the shadow is shown. This doesn't. The objects look weirdly lit and there are no shadows.

let worldGroundPlaneGeometry = SCNPlane(width: 1000, height: 1000)
    worldGroundPlaneGeometry.firstMaterial?.colorBufferWriteMask = SCNColorMask(rawValue: 0)
    let worldGroundPlane = SCNNode()

    worldGroundPlane.geometry = worldGroundPlaneGeometry
    worldGroundPlane.position = worldPosition
    worldGroundPlane.castsShadow = true
    worldGroundPlane.eulerAngles = SCNVector3(Float.pi / 2, 0, 0)
    self.addChildNode(worldGroundPlane)

    // Create a ambient light
    let ambientLight = SCNNode()
    ambientLight.light = SCNLight()
    ambientLight.light?.color = UIColor.white
    ambientLight.light?.type = SCNLight.LightType.ambient
    ambientLight.position = SCNVector3(x: 0,y: 5,z: 0)

    // Create a directional light node with shadow
    let directionalNode = SCNNode()
    directionalNode.light = SCNLight()
    directionalNode.light?.type = SCNLight.LightType.directional
    directionalNode.light?.color = UIColor.white
    directionalNode.light?.castsShadow = true
    directionalNode.light?.automaticallyAdjustsShadowProjection = true
    directionalNode.light?.shadowSampleCount = 64
    directionalNode.light?.shadowMode = .deferred
    directionalNode.light?.shadowMapSize = CGSize(width: 2048, height: 2048)
    directionalNode.light?.shadowColor = UIColor.black.withAlphaComponent(0.75)
    directionalNode.position = SCNVector3(x: 0,y: 5,z: 0)

    // Add the lights to the container
    self.addChildNode(ambientLight)
    self.addChildNode(directionalNode)

It needs to look like this in the whole scene:

P.S. The object and shadow look the same if I render it on my phone inside the app.

I Hope you can help me find a solution to achieve the goal described above.

I hope you can help me! Thanks ????

EDIT:

The solution provided below is not the solution. Now my scene looks like this with still no shadow:

the code:

let worldGroundPlaneGeometry = SCNPlane(width: 1000, height: 1000)
    let worldGroundPlane = SCNNode()
    worldGroundPlane.geometry?.firstMaterial?.lightingModel = .constant
    worldGroundPlane.geometry?.firstMaterial?.writesToDepthBuffer = true
    worldGroundPlane.geometry?.firstMaterial?.colorBufferWriteMask = []
    worldGroundPlane.geometry = worldGroundPlaneGeometry
    worldGroundPlane.position = worldPosition
    worldGroundPlane.castsShadow = true
    worldGroundPlane.eulerAngles = SCNVector3(Float.pi / 2, 0, 0)
    self.addChildNode(worldGroundPlane)

    // Create a ambient light
    let ambientLight = SCNNode()
    ambientLight.light = SCNLight()
    ambientLight.light?.shadowMode = .deferred
    ambientLight.light?.color = UIColor.white
    ambientLight.light?.type = SCNLight.LightType.ambient
    ambientLight.position = SCNVector3(x: 0,y: 5,z: 0)

    // Create a directional light node with shadow
    let directionalNode = SCNNode()
    directionalNode.light = SCNLight()
    directionalNode.light?.type = SCNLight.LightType.directional
    directionalNode.light?.color = UIColor.white
    directionalNode.light?.castsShadow = true
    directionalNode.light?.automaticallyAdjustsShadowProjection = true
    directionalNode.light?.shadowSampleCount = 64
    directionalNode.light?.shadowMode = .deferred
    directionalNode.light?.shadowMapSize = CGSize(width: 2048, height: 2048)
    directionalNode.light?.shadowColor = UIColor.black.withAlphaComponent(0.75)
    directionalNode.position = SCNVector3(x: 0,y: 5,z: 0)

    // Add the lights to the container
    self.addChildNode(ambientLight)
    self.addChildNode(directionalNode)
2
I'm not sure what the question actually is? Are you looking for the way to "uncheck the Red, Green, Blue and Alpha at the "write to color" option in the material inspector"? Or do you have another issue? If so, please describe your issue precisely, telling us (ideally, showing us), what you would like it to look like, and what it currently looks like.jcaron
Hi @jcaron. thanks for your reply. I changed the question quite a bit to make it more clear. I hope this helps. Thanks!Joost
Not the solution...@mnuagesJoost
try -Float.pi/2Alok Subedi

2 Answers

4
votes

I was playing around with your lighting setup and found the ambient light gave it a very washed out look... & the shadow seemed too unnaturally dark.

enter image description here

Anwway I tweaked your light setup configuration to the following. I got rid of the ambient light all together, and I added a constraint on the object node (timber box) is this case. I also controlled the lighting intensity with just one directional light.

        let directionalNode = SCNNode()
        let constraint = SCNLookAtConstraint(target:node)
        directionalNode.light = SCNLight()
        directionalNode.light?.type = .directional
        directionalNode.light?.color = UIColor.white
        directionalNode.light?.castsShadow = true
        directionalNode.light?.intensity = 2000
        directionalNode.light?.shadowRadius = 16
        directionalNode.light?.shadowMode = .deferred
        directionalNode.eulerAngles = SCNVector3(Float.pi/2,0,0)
        directionalNode.light?.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3)
        directionalNode.position = SCNVector3((node?.position.x)! + 10,(node?.position.y)! + 30,(node?.position.z)!+30)
        directionalNode.constraints = [constraint]
        // Add the lights to the container
        self.sceneView.scene.rootNode.addChildNode(directionalNode)
1
votes

The problem was that I wasn't actually using the material. Working Code:

 let worldGroundPlaneGeometry = SCNFloor()
    let worldGroundPlane = SCNNode()
    let worldGroundMaterial = SCNMaterial()
    worldGroundMaterial.lightingModel = .constant
    worldGroundMaterial.writesToDepthBuffer = true
    worldGroundMaterial.colorBufferWriteMask = []
    worldGroundMaterial.isDoubleSided = true
    worldGroundPlaneGeometry.materials = [worldGroundMaterial]

    worldGroundPlane.geometry = worldGroundPlaneGeometry        
    self.addChildNode(worldGroundPlane)

    // Create a ambient light
    let ambientLight = SCNNode()
    ambientLight.light = SCNLight()
    ambientLight.light?.shadowMode = .deferred
    ambientLight.light?.color = UIColor.white
    ambientLight.light?.type = SCNLight.LightType.ambient
    ambientLight.position = SCNVector3(x: 0,y: 5,z: 0)

    // Create a directional light node with shadow
    let directionalNode = SCNNode()
    directionalNode.light = SCNLight()
    directionalNode.light?.type = SCNLight.LightType.directional
    directionalNode.light?.color = UIColor.white
    directionalNode.light?.castsShadow = true
    directionalNode.light?.automaticallyAdjustsShadowProjection = true
    directionalNode.light?.shadowSampleCount = 64
    directionalNode.light?.shadowRadius = 16
    directionalNode.light?.shadowMode = .deferred
    directionalNode.light?.shadowMapSize = CGSize(width: 2048, height: 2048)
    directionalNode.light?.shadowColor = UIColor.black.withAlphaComponent(0.75)
    directionalNode.position = SCNVector3(x: 0,y: 5,z: 0)
    directionalNode.eulerAngles = SCNVector3(-Float.pi / 2, 0, 0)

    // Add the lights to the container

    self.addChildNode(ambientLight)
    self.addChildNode(directionalNode)