0

my basic code is pretty much this on that tutorial: https://code.tutsplus.com/tutorials/an-introduction-to-scenekit-fundamentals--cms-23847

I want to make a sunrise behaviour. Something like the lightNode begins on the same height as the constrained cubeNode and move it up so that the shadow shall become smaller over time. Therefore I tried to move the nodes via SCNAction.move(to...).

Action on lightNode -> nothing happens

Action on the constrained cubeNode -> shadow starts to flicker, but no changing

I tried around with the shadowModes. I think I misunderstood this. No useful results came up.

Has anyone an idea if scenekit supports something like dynamicly changing shadows?

Alexander Langer
  • 320
  • 2
  • 11
  • Please show us what you so-call a rising sun looks like in a picture. – El Tomato Mar 10 '17 at 22:36
  • Here I found a video that shows the shadow moving effect I want to create with Scenekit: https://www.youtube.com/watch?v=305b3X_FDZM – Alexander Langer Mar 10 '17 at 22:51
  • After view the said YouTube video, I have more questions than an answer. Now, I'm not sure what part in video you want to create with a cube. Additionally, when you say "Action on lightNode -> nothing happens," it's hard for one to say anything since you show no line of code. Without additional information, I propose that this topic be closed. – El Tomato Mar 10 '17 at 23:15
  • It is like in the code in the linked description. It is just about the question: When you put a spotlight somewhere into the SCNScene, is it possible to move the spotlight in a way that shadows are dynamically changed. It is just a general question. I have nothing found yet on internet. I tried to move spotlights via SCNActions in any combination, either the constraint node or the light node. Nothing worked and I have no clue so far if that is an option what might work at all. So I have nothing to offer or show what might help into the direction.. – Alexander Langer Mar 10 '17 at 23:58

2 Answers2

1

I found a way to make it. My major mistakes were:

  1. Somehow it does not work to access the lightNode (it just has no effect, when actions for a lightNode are called)

  2. I tried to go via SCNAction.move(to...). The answer is to use a rotation instead of a longitudinal movement.

The answer was accessing the constraint Node (instead of the lightNode). In this code the cubeNode is replaced with an invisible centerPoint (as the constraint node where the lightNode has to look at). A boxNodehas been added for making a canvas for the shadow. The lightNodehas to be added to the centerPoint, NOT to the scene.

There is the modified viewDidLoad-method. If you want to check this out, open Xcode, start a new project as SceneKit Game and replace the viewDidLoad with the following code.

    override func viewDidLoad() {
    super.viewDidLoad()

    // create a new scene
    let scene = SCNScene(named: "art.scnassets/ship.scn")!

    // create and add a camera to the scene
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    scene.rootNode.addChildNode(cameraNode)

    // place the camera
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

    // create and add a light to the scene
    let centerPoint = SCNNode.init()
    centerPoint.position = SCNVector3Make(0, 0, 0)
    scene.rootNode.addChildNode(centerPoint)

    let light = SCNLight()
    light.type = SCNLight.LightType.spot
    light.spotInnerAngle = 30
    light.spotOuterAngle = 80
    light.castsShadow = true
    light.color = UIColor.init(colorLiteralRed: 0.95, green: 0.8, blue: 0.8, alpha: 1)
    light.zFar = 200

    let lightNode = SCNNode()
    lightNode.light = light
    lightNode.position = SCNVector3Make(20, 100, 50)

    let constraint = SCNLookAtConstraint(target: centerPoint)
    constraint.isGimbalLockEnabled = true
    lightNode.constraints = [constraint]
    centerPoint.addChildNode(lightNode)

    let ambientLight = SCNLight.init()
    ambientLight.type = SCNLight.LightType.ambient
    ambientLight.color = UIColor.darkGray

    scene.rootNode.light = ambientLight

    // retrieve the ship node
    let material = SCNMaterial.init()
    material.diffuse.contents = UIColor.yellow
    material.lightingModel = SCNMaterial.LightingModel.phong
    material.locksAmbientWithDiffuse = true

    let boxNode = SCNNode.init(geometry: SCNBox.init(width: 10, height: 0.1, length: 10, chamferRadius: 0))
    boxNode.geometry?.firstMaterial = material
    boxNode.position = SCNVector3Make(0, -2, 0)

    scene.rootNode.addChildNode(boxNode)

    // animate spot light rotation
    centerPoint.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: CGFloat(M_PI), y: 0, z: CGFloat(M_PI), duration: 5)))

    // animate color light change
    let lightColorChange: CABasicAnimation = CABasicAnimation.init(keyPath: "color")
    lightColorChange.fromValue = UIColor.init(colorLiteralRed: 0.95, green: 0.8, blue: 0.8, alpha: 1)
    lightColorChange.toValue = UIColor.init(colorLiteralRed: 0, green: 0, blue: 0.4, alpha: 1)
    lightColorChange.duration = 5.0
    lightColorChange.autoreverses = true
    lightColorChange.repeatCount = Float.infinity
    light.addAnimation(lightColorChange, forKey: "changeLight")

    // retrieve the SCNView
    let scnView = self.view as! SCNView

    // set the scene to the view
    scnView.scene = scene

    // allows the user to manipulate the camera
    scnView.allowsCameraControl = true

    // show statistics such as fps and timing information
    scnView.showsStatistics = true

    // configure the view
    scnView.backgroundColor = UIColor.black

    // add a tap gesture recognizer
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
    scnView.addGestureRecognizer(tapGesture)
}

There is also a color change of the light is considered. With a CABasicAnimation it is possible to change the light.color-property over time. It is not like a perfect sunrise with all color steps, but there is also a way to chain those animations to make it more complex. (For this search for "wenderlich how to create a complex loading animation".

But I did not find a way to change the shadow color. It could be a nice effect to have white shadows on nighttime and black shadows on daytime. light.shadowColor did not help yet. If someone has an idea it is very appreciated.

Alexander Langer
  • 320
  • 2
  • 11
1

Yes. You can make a beautiful moving shadow. If your spotlight isn't moving it may be because the tutorial had you put a constraint on it. Try removing it.

// lightNode.constraints = [constraint]
Jon Allee
  • 316
  • 2
  • 4
  • Thank you for your answer. I tried this with all light types. With `omni`and `directional`it works when I move the `lightNode`. But it only creates shadows on the surface like this: http://www.directupload.net/file/d/4657/oajhkka8_png.htm `ambient` does not give an option for making shadows. And - to be honest - with `spot` I was not able to calibrate the light spot onto the object manually (lol). Without the constraining I have no clue how I can make a right positioning for a spotlight. But with `spot` you can make this: http://www.directupload.net/file/d/4657/yh7e52ok_png.htm – Alexander Langer Mar 11 '17 at 02:04
  • But I noticed that the `SCNAction.move(to...)` brings the wrong effect. But a rotation works very much like the sunrise effect I was looking for. I posted a code where it works. By the way, do you know to make a better rendering of the shadow spots on the ground? I tried to go with `light.shadowSampleCount = 10`, but the shadow disappeared and the performance of the app became aweful. – Alexander Langer Mar 11 '17 at 02:27
  • Try setting zNear on the spotlight. – Jon Allee Mar 12 '17 at 09:37