'Make SceneKit light move with camera
I'm trying to achieve a spotlight effect whereby the model is illuminated from the camera's point of view.
In other words, the camera should have a light that always points at the model.
However, the model is always illuminated as if from a stationary light source rather than a dynamic one. The same surfaces of the model are illuminated regardless of the camera's position. If I rotate the camera to the back of the model, all I see is black.
I've seen several other SO questions on this topic, but they did not solve my problem.
In viewDidLoad:
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
let light = SCNLight()
light.type = .directional //I've tried the other options, here, to no avail.
light.color = UIColor.init(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.7)
light.castsShadow = true
cameraNode.light = light
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
let scnView = self.view as! SCNView
scnView.pointOfView = cameraNode
To move the camera, I'm using the default camera controls via allowsCameraControl = true.
Question: How can I achieve the desired behavior, whereby the camera illuminates the model like a flashlight?
Thank you!
Solution 1:[1]
I got this working by doing the following:
- Gave the light its own node, separate from the camera.
- Added a look-at constraint so the node holding the light always points at the model.
- Set up the
SCNSceneRendererDelegateprotocol and implementedrenderer(_:updateAtTime:). Inside it, set thepositionof the node holding the light to the camera node'sposition.
Here's what the node configuration looks like:
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
let lightTargetNode = SCNNode()
lightTargetNode.position = SCNVector3(x: 0.0, y: 0.0, z: 0.0)
scene.rootNode.addChildNode(lightTargetNode)
let lightHolder = SCNNode()
let light = SCNLight()
light.type = .directional
light.color = UIColor.init(red: 255/255, green: 255/255, blue: 255/255, alpha: 0.7)
light.castsShadow = false
let lightConstraint = SCNLookAtConstraint(target: lightTargetNode)
lightHolder.constraints = [lightConstraint]
lightHolder.light = light
lightHolder.name = "lightHolder"
scene.rootNode.addChildNode(lightHolder)
lightHolder.position = SCNVector3(0, 0, 15)
This is a heavy-handed technique; it'd be a lot better to achieve this effect without using SCNSceneRendererDelegate, but this is the only way I was able to get this working.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | West1 |
