Can you change the properties of scnView.autoenablesDefaultLighting? - ios

I need lights to stay "stationary" in my scene. The best lighting method I've found so far is to actually to use scnView.autoenablesDefaultLighting = true however, I can't figure out if there's any way to control some of the attributes. The intensity of the light is a BIT too bright, the location of the light is a BIT different than where I'd like it to be, those kinds of properties.
I've tried using all sorts of other lights, coding them individually BUT since they add to the scene as nodes, the lights (in those cases) themselves will move when I set scnView.allowsCameraControl = true. The default lighting is the only one that will remain "stationary" once the user begins to move the camera around. Can you access/control the properties of the default lighting?

Forget allowsCameraControl and default cameras and lights if you want control of your scene.
let sceneView = SCNView()
let cameraNode = SCNNode() // the camera
var baseNode = SCNNode() // the basic model-root
let keyLight = SCNLight() ; let keyLightNode = SCNNode()
let ambientLight = SCNLight() ; let ambientLightNode = SCNNode()
func sceneSetup() {
let scene = SCNScene()
// add to an SCNView
sceneView.scene = scene
// add the container node containing all model elements
sceneView.scene!.rootNode.addChildNode(baseNode)
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(0, 0, 50)
scene.rootNode.addChildNode(cameraNode)
keyLight.type = SCNLightTypeOmni
keyLightNode.light = keyLight
keyLightNode.position = SCNVector3(x: 10, y: 10, z: 5)
cameraNode.addChildNode(keyLightNode)
ambientLight.type = SCNLightTypeAmbient
let shade: CGFloat = 0.40
ambientLight.color = UIColor(red: shade, green: shade, blue: shade, alpha: 1.0)
ambientLightNode.light = ambientLight
cameraNode.addChildNode(ambientLightNode)
// view the scene through your camera
sceneView.pointOfView = cameraNode
// add gesture recognizers here
}
Move or rotate cameraNode to effect motion in view. Or, move or rotate baseNode. Either way, your light stay fixed relative to the camera.
If you want your lights fixed relative to the model, make them children of baseNode instead of the camera.

If someone who wondering how to setup entire scene with new Scenekit integration with swift ui go though this. This work fine.
struct TestControllerNew: View {
let sceneView = SCNView()
let cameraNode = SCNNode()
var baseNode = SCNNode()
let id = "D69A09F8-EA80-4231-AD35-4A9908B4343C"
var scene = SCNScene()
var body: some View {
SceneView(
scene: sceneSetup(),
pointOfView: cameraNode,
options: [
.autoenablesDefaultLighting
]
)
}
func getTermsOfUseURL() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0].appendingPathComponent("\(id).usdz")
}
func sceneSetup() -> SCNScene {
let scene = try! SCNScene(url: getTermsOfUseURL())
// add to an SCNView
sceneView.scene = scene
// add the container node containing all model elements
sceneView.scene!.rootNode.addChildNode(baseNode)
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(0, 1, 10)
scene.rootNode.addChildNode(cameraNode)
// view the scene through your camera
sceneView.pointOfView = cameraNode
// add gesture recognizers here
return scene
}
}
Here the USDZ file get from document directory as a URL, you can use name instead of that.

Related

How to animate the background color of a scene view (SCNView). Note, not a scene (SCNScene), or conventional UIView

Is it possible to animate the .backgroundColor property of an SCNView?
Please note, it is easy to animate the background of an actual scene (SCNScene) and I know how to do that. It is also easy to animate the background of a conventional UIView.
I've not been able to figure out how to animate the .backgroundColor property of an SCNView.
Assuming you take the default SceneKit Game Template (the one with the rotating Jet) I got it working by doing this:
Here is my viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene() // 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 lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// retrieve the ship node
// let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
// animate the 3d object
// ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
// 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 initial background color of the SCNView
scnView.backgroundColor = UIColor.red
// Setup a SCNAction that rotates i.Ex the HUE Value of the Background
let animColor = SCNAction.customAction(duration: 10.0) { _ , timeElapsed in
scnView.backgroundColor = UIColor.init(hue: timeElapsed/10, saturation: 1.0, brightness: 1.0, alpha: 1.0)
}
// Run the Action (here using the rootNode)
scene.rootNode.runAction(animColor)
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
This might not be the best solution, but using a SCNTransaction I had no luck. Hope I could help in some way.
Just an addendum to the amazing & correct answer of #ZAY.
You have to do a frame-by-frame animation of the color and,
For some reason,
You do the action on the scene view
But. You run the action on the root node of the scene.
So, it's a miracle.
Works perfectly.

I have added a Human 3d Model in Scene Kit , its background is black how to make it as white as front view?

I have added a Human 3d Model in Scene Kit. Its background is black how to make it as white as front view? I have used this in swift app, used scene kit and human 3d model, Please check image I have attached..
Back View
3d Model Settings
Code :-
//MARK: - Scene Related Methods
func loadScene() {
self.removeExistingNodes()
loadSceneLayer(fileName: "FinalBaseMesh.obj")
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = false
load3DScene()
//layerSelectionIndex = 0
sceneView.scene = scene
}
func load3DScene() {
sceneView.scene = scene
// Allow user to manipulate camera
sceneView.allowsCameraControl = true
sceneView.backgroundColor = UIColor.white
sceneView.cameraControlConfiguration.allowsTranslation = true
sceneView.cameraControlConfiguration.panSensitivity = 0.9
sceneView.delegate = self as SCNSceneRendererDelegate
// sceneView.isPlaying = true
for reco in sceneView.gestureRecognizers! {
if let panReco = reco as? UIPanGestureRecognizer {
panReco.maximumNumberOfTouches = 1
}
}
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action:#selector(handleTap(_:)))
sceneView.addGestureRecognizer(tapGesture)
self.addSavedNode()
}
func loadSceneLayer(fileName: String) {
scene = SCNScene(named: fileName) ?? SCNScene()
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 6.5, z: 20)
scene.rootNode.addChildNode(cameraNode)
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .omni
lightNode.position = SCNVector3(x: 0, y: 6.5, z: 20)
scene.rootNode.addChildNode(lightNode)
// 6: Creating and adding ambien light to scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light?.type = .ambient
ambientLightNode.light?.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
}
I forgot to add last method please check loadstonelayer method
Remove all the camera control code
See How to rotate object in a scene with pan gesture - SceneKit for rotating an object
Put in a light node at a negative z facing the object

apply force on scnnode without loosing it on collision

I'm trying to create some simple logic on scenekit but without luck so far.
I have a sphere and between two planes. The sphere as dynamic physic body and the two planes contains static physic body.
I'm applying force on the sphere towards one of the planes. on collision the sphere bounces from the plane to the opposite direction but it losses lots of the force. how can I make it to keep the force on collision. This is the viewDidLoadCode that is generated in xCode on Game template with my changes:
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 lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "sphere", recursively: true)!
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
ship.physicsBody?.applyForce(SCNVector3(x: 100,y: 0, z: 0), asImpulse: false)
// 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)
}
the scn file
simulator
Set the restitution property of the physicsbody.
https://developer.apple.com/documentation/scenekit/scnphysicsbody/1514740-restitution
“This property simulates the “bounciness” of a body. A restitution of 1.0 means that the body loses no energy in a collision—for example, a ball dropped onto a flat surface will bounce back to the height it fell from. A restitution of 0.0 means the body does not bounce after a collision. A restitution of greater than 1.0 causes the body to gain energy in collisions. The default restitution is 0.5.”
Additionally you may want to reduce the .friction and .rollingFriction properties.

SCNNode scale resets when animation plays using a dae file

I am currently trying to use a dae file in scenekit for my model as well as my animations. When I try to scale the model, it initially scales correctly. After the animation starts playing, it resets to the original scale. Here is what I am trying to do at the moment:
let sceneView = SCNView()
sceneView.frame = self.view.bounds
sceneView.backgroundColor = UIColor.clearColor()
self.view.addSubview(sceneView)
//Add stuff to scene view
let scene = SCNScene()
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
sceneView.scene = scene
if let assetScene = SCNScene(named: "halfCircle.dae") {
if let node = assetScene.rootNode.childNodeWithName("pTorus1", recursively: true) {
node.scale = SCNVector3(x: 0.2, y: 0.2, z: 0.2)
scene.rootNode.addChildNode(node)
}
}
Any idea what is going on here?
Thanks.

Scene not rendering properly in SceneKit

I created a floor in a scene and loaded a collada file(.dae) into my scene and tried to create a plane below that model. But I have problems like below.
This problem generates only when custom camera is used. Scene renders properly when system camera is used i.e if no custom camera is added
My code is as below:
import UIKit import SceneKit
class TestVC: UIViewController, SCNSceneRendererDelegate {
var cameraNode: SCNNode!
var modelNode: SCNNode!
var scnView: SCNView!
var camNode: SCNNode!
var cameraPosition: SCNVector3!
override func viewDidLoad() {
super.viewDidLoad()
scnView = SCNView(frame: self.view.frame)
scnView.delegate = self
view.addSubview(scnView)
scnView.delegate = self
let scene = SCNScene()
scnView.scene = scene
//camera
let camera = SCNCamera()
cameraNode = SCNNode()
cameraNode.camera = camera
camera.zFar = 1000
cameraPosition = SCNVector3(0, 100, 150)
cameraNode.position = cameraPosition
scene.rootNode.addChildNode(cameraNode)
//floor
let floor = SCNFloor()
floor.reflectivity = 0
let floorNode = SCNNode(geometry: floor)
let firstmaterial = SCNMaterial()
firstmaterial.diffuse.contents = UIImage(named: "art.scnassets/grass.jpg")
firstmaterial.diffuse.wrapS = SCNWrapMode.Repeat
firstmaterial.diffuse.wrapT = SCNWrapMode.Repeat
floor.materials = [firstmaterial]
scene.rootNode.addChildNode(floorNode)
let light = SCNLight()
let lightNode = SCNNode()
lightNode.light = light
light.type = SCNLightTypeAmbient
light.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(lightNode)
let light1 = SCNLight()
let light1Node = SCNNode()
light1Node.light = light1
light1Node.position = SCNVector3(0, 200, -100)
light1.type = SCNLightTypeOmni
scene.rootNode.addChildNode(light1Node)
let modelScene = SCNScene(named: "Barcelona Chair.dae")
let solNode = modelScene?.rootNode
solNode?.eulerAngles = SCNVector3(GLKMathDegreesToRadians(-90), 0, 0)
scene.rootNode.addChildNode(solNode!)
scnView.allowsCameraControl = true
let plane = SCNPlane(width: 100, height: 100)
let planeNode = SCNNode(geometry: plane)
planeNode.pivot = SCNMatrix4MakeRotation(Float(M_PI_2), 1, 0, 0)//(CGFloat(M_PI_2), 1, 0, 0)
planeNode.position = SCNVector3(0, 1, 0)
plane.firstMaterial?.diffuse.contents = UIColor.redColor()
scene.rootNode.addChildNode(planeNode)
}
What you're probably seeing is known as "z-fighting". Basically, your floor and your plane are coexisting - they are coplanar - so the rendering of them is ambiguous. Try lifting the plane up a little by setting its position higher than the floor plane, and you should see this problem go away.
Don't know why the above problem exists but I got a different way of doing the thing. You can use SCNShape to draw an overlay over a floor. I drew a rectangular path using UIBezierPath and set the path property of the SCNShape class. :)

Resources