SceneKit Fully Stop Simulation from Running at Instant? - ios

Trying to get this simple rolling ball simulation running. I cannot seem to find a way to make the ball stop rolling at a said instant, then reset it to the start position with the isResting flag updating just as fast. when running, if the reset button is pressed the ball goes back to the start position but if it is not done rolling it will continue to roll. That is not desired.
import Cocoa
import SceneKit
class AppController : NSObject {
#IBOutlet weak var _sceneView: SCNView!
#IBOutlet weak var _pushButton: NSButton!
#IBOutlet weak var _resetButton: NSButton!
private let _radius = 25.0
private let _mySphereNode = SCNNode()
override func awakeFromNib() {
// assign empty scene
_sceneView.scene = SCNScene()
// setup the sphere
let mySphere = SCNSphere(radius: CGFloat(_radius))
mySphere.geodesic = true
mySphere.segmentCount = 50
mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
// create node for adding sphere
_mySphereNode.position = SCNVector3(0.0, CGFloat(_radius), 0.0)
_mySphereNode.geometry = mySphere
// add physics
let spherePhysicsBody = SCNPhysicsBody.dynamicBody()
spherePhysicsBody.mass = 0.67 // Kg
spherePhysicsBody.friction = 0.3765
spherePhysicsBody.rollingFriction = 0.2734
spherePhysicsBody.damping = 0.5
_mySphereNode.physicsBody = spherePhysicsBody
// attach the sphere node to the scene's root node
_sceneView.scene!.rootNode.addChildNode(_mySphereNode)
// setup ambient light source
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
// add ambient light the scene
_sceneView.scene!.rootNode.addChildNode(ambientLightNode)
// setup onmidirectional light
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLightTypeOmni
omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
_sceneView.scene!.rootNode.addChildNode(omniLightNode)
// add plane
let myPlane = SCNPlane(width: 125.0, height: 2000.0)
myPlane.widthSegmentCount = 10
myPlane.heightSegmentCount = 10
myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
let planeNode = SCNNode()
planeNode.geometry = myPlane
// rotote -90.0 degrees about the y-axis, then rot
var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
planeNode.transform = rotMat
planeNode.position = SCNVector3Make(0.0, 0.0, 0.0)
// add physcis to plane
planeNode.physicsBody = SCNPhysicsBody.staticBody()
// add plane to scene
_sceneView.scene!.rootNode.addChildNode(planeNode)
}
#IBAction func moveBall(sender: AnyObject) {
if _mySphereNode.physicsBody!.isResting == true {
let forceApplied = SCNVector3Make(40.0, 0.0, 0.0)
_mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
}
else {
print("Ball not at rest!")
}
}
#IBAction func resetBall(sender: AnyObject) {
_mySphereNode.physicsBody!.resetTransform()
}
}
Is there a way to stop the SceneKit simulation dead stop and reset to a start position in a way that would force the isResting flag to update to true as well?

I found that invalidating the node's geometry and physics body, then reattaching them worked out. Here is the code:
import Cocoa
import SceneKit
class AppController : NSObject {
#IBOutlet weak var _sceneView: SCNView!
#IBOutlet weak var _pushButton: NSButton!
#IBOutlet weak var _resetButton: NSButton!
private let _mySphereNode = SCNNode()
private func setupScene() {
// setup ambient light source
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
// add ambient light the scene
_sceneView.scene!.rootNode.addChildNode(ambientLightNode)
// setup onmidirectional light
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLightTypeOmni
omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
_sceneView.scene!.rootNode.addChildNode(omniLightNode)
// add plane
let myPlane = SCNPlane(width: 125.0, height: 2000.0)
myPlane.widthSegmentCount = 10
myPlane.heightSegmentCount = 10
myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
let planeNode = SCNNode()
planeNode.geometry = myPlane
// rotote -90.0 degrees about the y-axis, then rot
var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
planeNode.transform = rotMat
planeNode.position = SCNVector3Make(0.0, 0.0, 0.0)
// add physcis to plane
planeNode.physicsBody = SCNPhysicsBody.staticBody()
// add plane to scene
_sceneView.scene!.rootNode.addChildNode(planeNode)
}
private func setupBall() {
let _radius = 25.0
// setup the sphere
let mySphere = SCNSphere(radius: CGFloat(_radius))
mySphere.geodesic = true
mySphere.segmentCount = 50
mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
_mySphereNode.position = SCNVector3(0.0, CGFloat(_radius), 0.0)
_mySphereNode.geometry = mySphere
// add physics
let spherePhysicsBody = SCNPhysicsBody.dynamicBody()
spherePhysicsBody.mass = 0.67 // Kg
spherePhysicsBody.friction = 0.3765
spherePhysicsBody.rollingFriction = 0.2734
spherePhysicsBody.damping = 0.5
_mySphereNode.physicsBody = spherePhysicsBody
}
private func stopBall() {
_mySphereNode.geometry = nil
_mySphereNode.physicsBody = nil
}
override func awakeFromNib() {
// assign empty scene
_sceneView.scene = SCNScene()
// attach the sphere node to the scene's root node
_sceneView.scene!.rootNode.addChildNode(_mySphereNode)
setupScene()
setupBall()
}
#IBAction func moveBall(sender: AnyObject) {
let forceApplied = SCNVector3Make(40.0, 0.0, 0.0)
if _mySphereNode.physicsBody?.isResting == true {
_mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
}
}
#IBAction func resetBall(sender: AnyObject) {
// remove the ball from the sphere node
stopBall()
// reset the ball
setupBall()
}
}

Related

Move camera to tapped SCNNode

I'm using SceneKit and Swift to try and move the camera so it's 'focused' on the selected node. I understand I have the defaultCameraController enabled but I was trying to adjust the camera's position via dolly, rotate and translateInCameraSpaceBy but there was no animated transition - it just jumped to the new position.
Is there anyway for the camera to glide into position like how Google Maps slides/then zooms over to a searched location?
Any help would be greatly appreciated :)
Here's my code:
import UIKit
import SceneKit
class ViewController: UIViewController {
var gameView: SCNView!
var scene: SCNScene!
var cameraNode: SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
// Scene
scene = SCNScene()
// Camera
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(0, 0, 10)
scene.rootNode.addChildNode(cameraNode)
// Light
/*
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .omni
lightNode.position = SCNVector3(0, 10, 2)
scene.rootNode.addChildNode(lightNode)
*/
// Stars
//let stars = SCNParticleSystem(named: "starsParticles.scnp", inDirectory: nil)!
//scene.rootNode.addParticleSystem(stars)
// Earth
let earthNode = itemPlate()
earthNode.position = SCNVector3(0, 0, 0)
scene.rootNode.addChildNode(earthNode)
// Create orbiting moonOne
let moonNodeOne = itemPlate()
moonNodeOne.position = SCNVector3(3, 0, 0)
earthNode.addChildNode(moonNodeOne)
// Create orbiting moonOne
let moonNodeTwo = itemPlate()
moonNodeTwo.position = SCNVector3(5, 3, 2)
earthNode.addChildNode(moonNodeTwo)
// Create orbiting moonOne
let moonNodeThree = itemPlate()
moonNodeThree.position = SCNVector3(-4, -3, 5)
earthNode.addChildNode(moonNodeThree)
// Scene formation
gameView = self.view as! SCNView
gameView.scene = scene
gameView.showsStatistics = true
gameView.allowsCameraControl = true
gameView.autoenablesDefaultLighting = true
gameView.defaultCameraController.interactionMode = .fly
gameView.defaultCameraController.inertiaEnabled = true
gameView.defaultCameraController.maximumVerticalAngle = 89
gameView.defaultCameraController.minimumVerticalAngle = -89
scene.background.contents = UIImage(named: "orangeBg.jpg")
}
override var prefersStatusBarHidden: Bool {
return true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in: gameView)
let hitList = gameView.hitTest(location, options: nil)
if let hitObject = hitList.first {
let node = hitObject.node
// Update camera position
//gameView.defaultCameraController.translateInCameraSpaceBy(x: node.position.x, y: node.position.y, z: node.position.z + 5)
let onScreenPoint:CGPoint = CGPoint(x: 1.0, y: 1.0)
let viewport:CGSize = CGSize(width: 50, height: 50)
gameView.defaultCameraController.dolly(by: 1.0, onScreenPoint: onScreenPoint, viewport: viewport)
//let newCameraPosition = SCNVector3Make(node.position.x, node.position.y, node.position.z + 10)
print("NODE_HIT_OBJECT_COORDS: \(node.position.x), \(node.position.y) \(node.position.y)")
//let moveToAction = SCNAction.move(by: newCameraPosition, duration: 1.0)
}
}
}
You can implement in your code a methodology like this (sorry, I used macOS project instead iOS, but it's almost the same):
func handleClick(_ gestureRecognizer: NSGestureRecognizer) {
let scnView = self.view as! SCNView
let p = gestureRecognizer.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
if hitResults.count > 0 {
let result = hitResults[0]
let nodePosition = result.node.position.z
var matrix = matrix_identity_float4x4
SCNTransaction.begin()
SCNTransaction.animationDuration = 1.5 // duration in seconds
matrix.columns.3.z = Float(nodePosition + 5.0)
scnView.pointOfView?.position.z = CGFloat(matrix.columns.3.z)
SCNTransaction.commit()
}
}
Or, as a second logical option, you can use SceneKit's constraints:
func handleClick(_ gestureRecognizer: NSGestureRecognizer) {
let scnView = self.view as! SCNView
let p = gestureRecognizer.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
if hitResults.count > 0 {
let result = hitResults[0]
let nodePosition = result.node
let constraint1 = SCNLookAtConstraint(target: nodePosition)
let constraint2 = SCNDistanceConstraint(target: nodePosition)
constraint2.minimumDistance = 5
constraint2.maximumDistance = 9
SCNTransaction.begin()
SCNTransaction.animationDuration = 1.5
scnView.pointOfView?.constraints = [constraint2, constraint1]
SCNTransaction.commit()
}
}
P.S. These two approaches ain't out-of-the-box solutions but rather hints on how to implement what you want to.

SCNNode releasing children with altered transform and pivot properties

I'm dealing with children nodes with pivot and position that have been altered. I found a lot of SCNNode transformation topics, but it seems none of them represent my situation.
I have six balls : (can't post more than 2 links, image is at i.stack.imgur.com/v3Lc4.png )
And I select the top four of them, adjust the pivot, adjust the position (to counter the pivot translation effect), and rotate. This is the code I use :
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action)
It did the job well :
Now, I need to release back the fourBalls child nodes into the rootNode, I use this code which I put as completion block :
//core problem
//how to release the node with the transform?
for node in fourBalls.childNodes
{ node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
And here comes the problem, I released them wrongly :
So my question is, how to release the children nodes to the rootNode with correct pivot, position, and transform properties?
Here is my full GameViewController.swift for you who want to try :
import SceneKit
class GameViewController: UIViewController {
let scene = SCNScene()
override func viewDidLoad() {
super.viewDidLoad()
let ball1 = SCNSphere(radius: 0.4)
let ball2 = SCNSphere(radius: 0.4)
let ball3 = SCNSphere(radius: 0.4)
let ball4 = SCNSphere(radius: 0.4)
let ball5 = SCNSphere(radius: 0.4)
let ball6 = SCNSphere(radius: 0.4)
ball1.firstMaterial?.diffuse.contents = UIColor.purple()
ball2.firstMaterial?.diffuse.contents = UIColor.white()
ball3.firstMaterial?.diffuse.contents = UIColor.cyan()
ball4.firstMaterial?.diffuse.contents = UIColor.green()
ball5.firstMaterial?.diffuse.contents = UIColor.black()
ball6.firstMaterial?.diffuse.contents = UIColor.blue()
let B1 = SCNNode(geometry: ball1)
B1.position = SCNVector3(x:-2,y:1,z:-5)
scene.rootNode.addChildNode(B1)
B1.name = "b1"
let B2 = SCNNode(geometry: ball2)
B2.position = SCNVector3(x:-1,y:1,z:-5)
scene.rootNode.addChildNode(B2)
B2.name = "b2"
let B3 = SCNNode(geometry: ball3)
B3.position = SCNVector3(x:-2,y:0,z:-5)
scene.rootNode.addChildNode(B3)
B3.name = "b3"
let B4 = SCNNode(geometry: ball4)
B4.position = SCNVector3(x:-1,y:0,z:-5)
scene.rootNode.addChildNode(B4)
B4.name = "b4"
let B5 = SCNNode(geometry: ball5)
B5.position = SCNVector3(x:-2,y:-1,z:-5)
scene.rootNode.addChildNode(B5)
B5.name = "b5"
let B6 = SCNNode(geometry: ball6)
B6.position = SCNVector3(x:-1,y:-1,z:-5)
scene.rootNode.addChildNode(B6)
B6.name = "b6"
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(-1.5,0,2)
scene.rootNode.addChildNode(cameraNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.yellow()
scene.rootNode.addChildNode(ambientLightNode)
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = false
scnView.backgroundColor = UIColor.orange()
//core code
let fourBalls = SCNNode()
for i in 1...4
{
let ball = scene.rootNode.childNode(withName: "b" + String(i), recursively: false)!
ball.removeFromParentNode()
fourBalls.addChildNode(ball)
}
scene.rootNode.addChildNode(fourBalls)
//adjust the pivot of the fourBalls node
fourBalls.pivot = SCNMatrix4MakeTranslation(-1.5, 0.5, -5)
//fix the position
fourBalls.position = SCNVector3Make(-1.5, 0.5, -5)
//rotate
let action = SCNAction.rotateBy(x: 0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.run(action, completionHandler:
{
//core problem
for node in fourBalls.childNodes
{
node.transform = node.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.current().userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
}
SCNActions update the presentation tree directly, not the model tree, this is probably best explained in the 2014 WWDC video (skip to 16:38). What this means is that throughout the animation the current transform for each of the animating nodes is only available from the presentationNode. Your code works if we get the transform from here instead.
Apologies for the Swift 2 backport...
//rotate
let action = SCNAction.rotateByX(0, y: 0, z: CGFloat(M_PI_2), duration: 2)
fourBalls.runAction(action, completionHandler: {
//core problem
for node in fourBalls.childNodes
{
node.transform = node.presentationNode.worldTransform
node.removeFromParentNode()
self.scene.rootNode.addChildNode(node)
}
})
TBH I was expecting node.worldTransform == node.presentationNode.worldTransform when it got to the completion handler.

SceneKit - Rotating around a point causing strange rotation

I want to be able to rotate a camera around a cube (a collection of cubes), but for some reason, when I rotate, the rotation goes in multiple directions.
I have an object that I wish to rotate around and set this as a look at constraint. This object is in the middle of the cubes.
I have a swipe gesture recogniser that does the rotation...but it's just off. I'm missing something...
import UIKit
import QuartzCore
import SceneKit
import AVFoundation
class GameViewController: UIViewController {
var scene:SCNScene!
var tiles:[SCNNode] = [SCNNode]()
var cameraNode:SCNNode!
var centerNode:SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
scene = SCNScene()
let sideMaterial = SCNMaterial()
sideMaterial.diffuse.contents = UIColor.greenColor()
sideMaterial.locksAmbientWithDiffuse = true;
let geom = SCNBox(width: 32, height: 32.0, length: 32, chamferRadius: 8.0)
geom.widthSegmentCount = 16
geom.heightSegmentCount = 16
geom.lengthSegmentCount = 16
geom.materials = [sideMaterial, sideMaterial, sideMaterial, sideMaterial, sideMaterial, sideMaterial]
centerNode = SCNNode(geometry: geom)
centerNode.position = SCNVector3(x: 4*32, y: -4*32, z: -4*32)
scene.rootNode.addChildNode(centerNode)
// create and add a camera to the scene
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: -4*32, y: -4*32, z: 4*32)
cameraNode.pivot = SCNMatrix4MakeTranslation(4*32, -4*32, -4*32)
cameraNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: 1.360646)
let lookAt = SCNLookAtConstraint(target: centerNode)
//lookAt.gimbalLockEnabled = true
cameraNode.constraints = [lookAt]
cameraNode.camera?.xFov = 90
cameraNode.camera?.yFov = 90
cameraNode.camera?.zNear = 1
cameraNode.camera?.zFar = 5000
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 4*32, y: -4*32, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
// retrieve the SCNView
let scnView = self.view as! SCNView
setupTiles()
// 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.blackColor()
// Add gestures
var gestureRecognizers = [UIGestureRecognizer]()
let swipeDownGesture = UISwipeGestureRecognizer(target: self, action: "swipe:")
swipeDownGesture.direction = UISwipeGestureRecognizerDirection.Down
gestureRecognizers.append(swipeDownGesture)
let swipeUpGesture = UISwipeGestureRecognizer(target: self, action: "swipe:")
swipeUpGesture.direction = UISwipeGestureRecognizerDirection.Up
gestureRecognizers.append(swipeUpGesture)
let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: "swipe:")
swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.Left
gestureRecognizers.append(swipeLeftGesture)
let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: "swipe:")
swipeRightGesture.direction = UISwipeGestureRecognizerDirection.Right
gestureRecognizers.append(swipeRightGesture)
if let existingGestureRecognizers = scnView.gestureRecognizers as? [UIGestureRecognizer] {
gestureRecognizers.extend(existingGestureRecognizers)
}
scnView.gestureRecognizers = gestureRecognizers
}
func swipe(gestureRecognize: UISwipeGestureRecognizer) {
var leftRight:Float = 0
var upDown:Float = 0
var amount:Float = 1.5707
switch gestureRecognize.direction
{
case UISwipeGestureRecognizerDirection.Up:
upDown = 1
break
case UISwipeGestureRecognizerDirection.Down:
upDown = -1
break
case UISwipeGestureRecognizerDirection.Left:
leftRight = -1
break
case UISwipeGestureRecognizerDirection.Right:
leftRight = 1
break
default:
break
}
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(3.0)
cameraNode.rotation = SCNVector4(x: leftRight, y: upDown, z: 0, w: amount)
SCNTransaction.commit()
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
// override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
// if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
// return UIInterfaceOrientationMask.AllButUpsideDown
// } else {
// return UIInterfaceOrientationMask.All
// }
// }
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
func setupTiles()
{
for z in 0...7
{
for y in 0...7
{
for x in 0...7
{
if y > 0 && y < 7 && z > 0 && z < 7 && x > 0 && x < 7
{
continue
}
let topMaterial = SCNMaterial()
topMaterial.diffuse.contents = UIColor.whiteColor()
topMaterial.locksAmbientWithDiffuse = true;
let sideMaterial = SCNMaterial()
sideMaterial.diffuse.contents = UIColor.whiteColor()
sideMaterial.locksAmbientWithDiffuse = true;
let geom = SCNBox(width: 32, height: 32.0, length: 32, chamferRadius: 8.0)
geom.widthSegmentCount = 16
geom.heightSegmentCount = 16
geom.lengthSegmentCount = 16
geom.materials = [topMaterial, sideMaterial, sideMaterial, sideMaterial, sideMaterial, sideMaterial]
let node = SCNNode(geometry: geom)
node.position = SCNVector3(x: Float(x) * 32.0, y: -(Float(y) * 32.0), z: -(Float(z) * 32.0))
scene.rootNode.addChildNode(node)
tiles.append(node)
}
}
}
}
}
Edit:
Setting the transform instead of the rotation seems to have better effects
centerNode = SCNNode(geometry: geom)
centerNode.transform = SCNMatrix4Identity
scene.rootNode.addChildNode(centerNode)
// create and add a camera to the scene
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 8*32)
cameraNode.pivot = SCNMatrix4MakeTranslation(0, 0, -8*32)
let lookAt = SCNLookAtConstraint(target: centerNode)
lookAt.gimbalLockEnabled = true
cameraNode.constraints = [lookAt]
cameraNode.transform = SCNMatrix4Identity
//In gesture
cameraNode.transform = SCNMatrix4Rotate(cameraNode.transform, amount, upDown, leftRight, 0)

Objects not affected by gravity field in SceneKit [duplicate]

I'm trying to use a SCNPhysicsField.linearGravityField object to affect only specific objects in my scene. The problem is, that I can't seem to get it to affect anything. Here's a sample of my code in Swift:
let downGravityCatagory = 1 << 0
let fieldDown = SCNPhysicsField.linearGravityField()
let fieldUp = SCNPhysicsField.linearGravityField()
let fieldNode = SCNNode()
let sceneView = view as! SCNView
sceneView.scene = scene
sceneView.scene!.physicsWorld.gravity = SCNVector3(x: 0, y: 0, z: 0)
fieldDown.categoryBitMask = downGravityCatagory
fieldDown.active = true
fieldDown.strength = 3
fieldNode.physicsField = fieldDown
scene.rootNode.addChildNode(fieldNode)
var dice = SCNNode()
//I then attach geometry here
dice.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Dynamic, shape: SCNPhysicsShape(geometry: dice.geometry!, options: nil))
dice.physicsBody?.categoryBitMask = downGravityCatagory
scene.rootNode.addChildNode(dice)
Even though the Physics Bodies are assigned the same catagoryBitMask as the gravity field, they just float there in zero G, only affected by the physicsworld gravity.
Set the "downGravityCatagory" bit mask on the node:
dice.categoryBitMask = downGravityCatagory;
the physics's categoryBitMask is for physics collisions only.
I am trying to get my ball to fall faster. Right now it falls really slowly. I tried using this answer. I think I am close, but I do not really know. The code:
import Cocoa
import SceneKit
class AppController : NSObject {
#IBOutlet weak var _sceneView: SCNView!
#IBOutlet weak var _pushButton: NSButton!
#IBOutlet weak var _resetButton: NSButton!
private let _mySphereNode = SCNNode()
private let _gravityFieldNode = SCNNode()
private let downGravityCategory = 1 << 0
private func setupScene() {
// setup ambient light source
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
// add ambient light the scene
_sceneView.scene!.rootNode.addChildNode(ambientLightNode)
// setup onmidirectional light
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLightTypeOmni
omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
_sceneView.scene!.rootNode.addChildNode(omniLightNode)
// add plane
let myPlane = SCNPlane(width: 125.0, height: 2000.0)
myPlane.widthSegmentCount = 10
myPlane.heightSegmentCount = 10
myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
let planeNode = SCNNode()
planeNode.geometry = myPlane
// rotote -90.0 degrees about the y-axis, then rotate -90.0 about the x-axis
var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
planeNode.transform = rotMat
planeNode.position = SCNVector3Make(0.0, 0.0, 0.0)
// add physcis to plane
planeNode.physicsBody = SCNPhysicsBody.staticBody()
// add plane to scene
_sceneView.scene!.rootNode.addChildNode(planeNode)
// gravity folks...
// first, set the position for field effect
let gravityField = SCNPhysicsField.linearGravityField()
gravityField.categoryBitMask = downGravityCategory
gravityField.active = true
gravityField.strength = 3.0
gravityField.exclusive = true
_gravityFieldNode.physicsField = gravityField
_sceneView.scene!.rootNode.addChildNode(_gravityFieldNode)
// attach the sphere node to the scene's root node
_mySphereNode.categoryBitMask = downGravityCategory
_sceneView.scene!.rootNode.addChildNode(_mySphereNode)
}
private func setupBall() {
let radius = 25.0
// sphere geometry
let mySphere = SCNSphere(radius: CGFloat(radius))
mySphere.geodesic = true
mySphere.segmentCount = 50
mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
// position sphere geometry, add it to node
_mySphereNode.position = SCNVector3(0.0, CGFloat(radius), 0.0)
_mySphereNode.geometry = mySphere
// physics body and shape
_mySphereNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(geometry: mySphere, options: nil))
_mySphereNode.physicsBody!.mass = 0.125
}
private func stopBall() {
_mySphereNode.geometry = nil
_mySphereNode.physicsBody = nil
}
override func awakeFromNib() {
// assign empty scene
_sceneView.scene = SCNScene()
setupScene()
setupBall()
}
#IBAction func moveBall(sender: AnyObject) {
let forceApplied = SCNVector3Make(35.0, 0.0, 0.0)
if _mySphereNode.physicsBody?.isResting == true {
_mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
}
else if _mySphereNode.physicsBody?.isResting == false {
print("ball not at rest...")
}
else {
print("No physics associated with the node...")
}
}
#IBAction func resetBall(sender: AnyObject) {
// remove the ball from the sphere node
stopBall()
// reset the ball
setupBall()
}
}
Is there some trick to get "real-world" type gravity?
Based on what #tedesignz suggested, here is the slightly modified working code:
import Cocoa
import SceneKit
class AppController : NSObject, SCNPhysicsContactDelegate {
#IBOutlet weak var _sceneView: SCNView!
#IBOutlet weak var _pushButton: NSButton!
#IBOutlet weak var _resetButton: NSButton!
private let _mySphereNode = SCNNode()
private let _myPlaneNode = SCNNode()
private let _gravityFieldNode = SCNNode()
private let BallType = 1
private let PlaneType = 2
private let GravityType = 3
private func setupScene() {
// setup ambient light source
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
// add ambient light the scene
_sceneView.scene!.rootNode.addChildNode(ambientLightNode)
// setup onmidirectional light
let omniLightNode = SCNNode()
omniLightNode.light = SCNLight()
omniLightNode.light!.type = SCNLightTypeOmni
omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
_sceneView.scene!.rootNode.addChildNode(omniLightNode)
// add plane
let myPlane = SCNPlane(width: 125.0, height: 150.0)
myPlane.widthSegmentCount = 10
myPlane.heightSegmentCount = 10
myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
_myPlaneNode.geometry = myPlane
// rotote -90.0 degrees about the y-axis, then rotate -90.0 about the x-axis
var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
_myPlaneNode.transform = rotMat
_myPlaneNode.position = SCNVector3Make(0.0, 0.0, 0.0)
// add physcis to plane
_myPlaneNode.physicsBody = SCNPhysicsBody(type: .Static, shape: SCNPhysicsShape(geometry: myPlane, options: nil))
// configure physics body
_myPlaneNode.physicsBody!.contactTestBitMask = BallType
_myPlaneNode.physicsBody!.collisionBitMask = BallType
_myPlaneNode.physicsBody!.categoryBitMask = PlaneType
// add plane to scene
_sceneView.scene!.rootNode.addChildNode(_myPlaneNode)
// add sphere node
_sceneView.scene!.rootNode.addChildNode(_mySphereNode)
// gravity folks...
// first, set the position for field effect
let gravityField = SCNPhysicsField.linearGravityField()
gravityField.categoryBitMask = GravityType
gravityField.active = true
gravityField.direction = SCNVector3(0.0, -9.81, 0.0)
print(gravityField.direction)
gravityField.strength = 10.0
gravityField.exclusive = true
_gravityFieldNode.physicsField = gravityField
_sceneView.scene!.rootNode.addChildNode(_gravityFieldNode)
// set the default gravity to zero vector
_sceneView.scene!.physicsWorld.gravity = SCNVector3(0.0, 0.0, 0.0)
}
private func setupBall() {
let radius = 25.0
// sphere geometry
let mySphere = SCNSphere(radius: CGFloat(radius))
mySphere.geodesic = true
mySphere.segmentCount = 50
mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
// position sphere geometry, add it to node
_mySphereNode.position = SCNVector3(0.0, CGFloat(radius), 0.0)
_mySphereNode.geometry = mySphere
// physics body and shape
_mySphereNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(geometry: mySphere, options: nil))
_mySphereNode.physicsBody!.mass = 0.125
_mySphereNode.physicsBody!.contactTestBitMask = PlaneType
_mySphereNode.physicsBody!.collisionBitMask = PlaneType
_mySphereNode.physicsBody!.categoryBitMask = (BallType | GravityType)
}
private func stopBall() {
_mySphereNode.geometry = nil
_mySphereNode.physicsBody = nil
}
override func awakeFromNib() {
// assign empty scene
_sceneView.scene = SCNScene()
// contact delegate
_sceneView.scene!.physicsWorld.contactDelegate = self
setupScene()
setupBall()
}
#IBAction func moveBall(sender: AnyObject) {
let forceApplied = SCNVector3Make(5.0, 0.0, 0.0)
if _mySphereNode.physicsBody?.isResting == true {
_mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
}
else if _mySphereNode.physicsBody?.isResting == false {
print("ball not at rest...")
}
else {
print("No physics associated with the node...")
}
}
#IBAction func resetBall(sender: AnyObject) {
// remove the ball from the sphere node
stopBall()
// reset the ball
setupBall()
}
/*** SCENEKIT DELEGATE METHODS ***/
func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
print("we have contact...")
}
func physicsWorld(world: SCNPhysicsWorld, didEndContact contact: SCNPhysicsContact) {
print("No longer touching...")
}
}

SCNView takes two seconds to show the scene when the app is opened

I am making a 3D game in SceneKit which is nearly finished. The app consists of one view which contains one SCNView and two small views with buttons.
I found out that when I launch the game it takes about two or three seconds after the launchscreen is gone to show the scene in the SCNView. I see a white screen with the buttons in the mean time. I load the main scene into the SCNView from a COLLADA file and add two nodes from another Collade file. I also add some nodes programmatically and add physics to some nodes. All of this happens in my viewDidLoad method.
The code I use:
#IBOutlet var scnView: SCNView!
#IBOutlet var soundButton: UIButton!
#IBOutlet var statsButton: UIButton!
var radAngle:Float = 0.0 // Angle of number
var maxAngle:Float = (120)/180 * Float(M_PI) // Angle of open numbers (up)
let dice1: SCNNode // die 1
let dice2: SCNNode // die 2
let leftCameraNode:SCNNode // Camera for rules
let rightCameraNode:SCNNode // Camera for box
let scoreCameraNode = SCNNode() // Camera for the statistics
var gameEndedNode: SCNNode = SCNNode() // Node when game ended game
var dices:[SCNNode] // The two dice nodes
var dicePreviousTotal:Int = 0 // thrown number (total)
var diceCurrentTotal:Int = 0 // compare with previous
var numberNames:[String] = ["numberBlock_1", "numberBlock_2", "numberBlock_3", "numberBlock_4", "numberBlock_5", "numberBlock_6", "numberBlock_7", "numberBlock_8", "numberBlock_9"] // Names of all NumberBlocks
var numbersUp:[Int] = [] // Indicate for every numbers if it is up (open)
var numbersRound:[Int] = [] // numbers from up to down this round
var longPressLocation:CGPoint = CGPointMake(0.0, 0.0) //location of long press
var gameState = 0 // 0:Ended, 1:Throwing, 2:Flipping
var soundMute = false // If sound is muted
var timesPlayed:Int = 0 // Times played the game
var timesShut:Int = 0 // Times that the box has been shut
var shutPercentage:Float = 0.0 // Percentage of above
let scene = SCNScene(named: "ShutTheBox.scnassets/ShutTheBox.dae")! // Scene of the box
let noteScene = SCNScene(named: "bladpotlood.scnassets/blad.dae")! // Scene of the rules note
var soundManager = SoundManager() // The class that manages the sound
var soundPlayed1 = false // Indicate if sound has been played this round for die 1
var soundPlayed2 = false // Indicate if sound has been played this round for die 2
let flickSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Flick", ofType: "m4a")!) // Flick sound
let diceSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Two Dice", ofType: "wav")!) // Diceroll sound
var timer: NSTimer = NSTimer() // Timer to check if the dice stopped rolling
var throwDuration:Float = 0.0 // Duration of one throw to prevent wrong throw
var gameEndedText:String = "" // String of text shown at game and
var scoreText:String = "" // String of text with the statistics
var scoreTextGeometry: SCNText = SCNText() // Geometry of above
var timesPlayedNode:SCNNode = SCNNode() // Node for above
let myGray = SCNMaterial() // Material Gray
let myWood = SCNMaterial() // Material Wood
required init(coder aDecoder: NSCoder) {
dice1 = scene.rootNode.childNodeWithName("Dice1", recursively: false)!
dice2 = scene.rootNode.childNodeWithName("Dice2", recursively: false)!
dices = [dice1,dice2]
leftCameraNode = noteScene.rootNode.childNodeWithName("Camera", recursively: false)!
rightCameraNode = scene.rootNode.childNodeWithName("Camera", recursively: false)!
myGray.diffuse.contents = UIColor.darkGrayColor()
myWood.diffuse.contents = UIImage(named: "LightWoodTexture.jpg")
super.init(coder:aDecoder)
}
func initGame() {
// -- Start a new game -- //
gameState = 1
numbersUp = [1,1,1,1,1,1,1,1,1]
dicePreviousTotal = 0
for number in numberNames {
scene.rootNode.childNodeWithName(number, recursively: false)!.eulerAngles = SCNVector3Make(-maxAngle, 0.0, 0.0)
}
}
override func viewDidLoad() {
super.viewDidLoad()
retreiveScore()
// Setup of scene
scnView.scene = scene
scnView.allowsCameraControl = false
scnView.showsStatistics = false
scnView.backgroundColor = UIColor.blackColor()
scene.physicsWorld.gravity = SCNVector3Make(0.0, -9.8, 0.0)
scene.physicsWorld.contactDelegate = self
// Setup camera to see statistics
scoreCameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(scoreCameraNode)
scoreCameraNode.position = SCNVector3Make(18.5, 9, 5)
scoreCameraNode.rotation = SCNVector4Make(-1.0, 0.0, 0.0, 1.00)
// create and add a light to the scene, remove existing
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 15, z: 10)
scene.rootNode.addChildNode(lightNode)
scene.rootNode.childNodeWithName("Lamp", recursively: false)?.removeFromParentNode()
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.blackColor()
scene.rootNode.addChildNode(ambientLightNode)
// add gamerules note and camera
let noteNode = SCNNode()
noteNode.addChildNode(noteScene.rootNode.childNodeWithName("Plane", recursively: false)!)
noteNode.addChildNode(leftCameraNode)
noteNode.position = SCNVector3Make(-12, 0.02, 0)
noteNode.rotation = SCNVector4Make(0.0, 1.0, 0.0, 0.2)
scene.rootNode.addChildNode(noteNode)
// create score text and node
if timesShut != 0 {
shutPercentage = Float(timesShut/timesPlayed * 100)
}
scoreText = "Times played:\t\(timesPlayed) \nShut the Box:\t\(shutPercentage)%"
scoreTextGeometry = SCNText(string: scoreText, extrusionDepth: 5)
scoreTextGeometry.font = UIFont(name: "Futura-CondensedExtraBold", size: 20)
scoreTextGeometry.chamferRadius = 0.8
scoreTextGeometry.materials = [myWood, myGray, myGray]
timesPlayedNode = SCNNode(geometry: scoreTextGeometry)
timesPlayedNode.scale = SCNVector3Make(0.05, 0.05, 0.05)
timesPlayedNode.rotation = SCNVector4Make(-1.0, 0.0, 0.0, Float(M_PI_4))
timesPlayedNode.position = SCNVector3Make(14.0, 0.0, 0.0)
timesPlayedNode.name = "timesPlayed"
scene.rootNode.addChildNode(timesPlayedNode)
// create boundary box
let floorBorderGeometry = SCNBox(width: 100, height: 4.0, length: 100, chamferRadius: 0.0)
let floorPhysicsShape = SCNPhysicsShape(geometry: floorBorderGeometry, options: nil)
let floorNode = SCNNode()
floorNode.position = SCNVector3Make(0.0, -1.85, 0.0)
floorNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: floorPhysicsShape)
scene.rootNode.addChildNode(floorNode)
floorNode.physicsBody!.friction = 0.8
floorNode.physicsBody!.categoryBitMask = 0b010
floorNode.physicsBody!.collisionBitMask = 0b100
let leftBorderGeometry = SCNBox(width: 4, height: 100, length: 100, chamferRadius: 0.0)
let leftBorderPhysicsShape = SCNPhysicsShape(geometry: leftBorderGeometry, options: nil)
let leftBorderNode = SCNNode()
leftBorderNode.position = SCNVector3Make(-9.32, 0, 0)
leftBorderNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: leftBorderPhysicsShape)
scene.rootNode.addChildNode(leftBorderNode)
leftBorderNode.physicsBody!.categoryBitMask = 0b001
leftBorderNode.physicsBody!.collisionBitMask = 0b100
let rightBorderNode = SCNNode()
rightBorderNode.position = SCNVector3Make(9.32, 0, 0)
rightBorderNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: leftBorderPhysicsShape)
scene.rootNode.addChildNode(rightBorderNode)
rightBorderNode.physicsBody!.categoryBitMask = 0b001
rightBorderNode.physicsBody!.collisionBitMask = 0b100
let frontBorderGeometry = SCNBox(width: 100, height: 100, length: 4, chamferRadius: 0.0)
let frontBorderPhysicsShape = SCNPhysicsShape(geometry: frontBorderGeometry, options: nil)
let frontBorderNode = SCNNode()
frontBorderNode.position = SCNVector3Make(0, 0, 7.85)
frontBorderNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: frontBorderPhysicsShape)
scene.rootNode.addChildNode(frontBorderNode)
frontBorderNode.physicsBody!.categoryBitMask = 0b001
frontBorderNode.physicsBody!.collisionBitMask = 0b100
let backBorderNode = SCNNode()
backBorderNode.position = SCNVector3Make(0, 0, -4.35)
backBorderNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: frontBorderPhysicsShape)
scene.rootNode.addChildNode(backBorderNode)
backBorderNode.physicsBody!.categoryBitMask = 0b001
backBorderNode.physicsBody!.collisionBitMask = 0b100
let topBorderNode = SCNNode()
topBorderNode.position = SCNVector3Make(0.0, 50.0, 0.0)
topBorderNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: floorPhysicsShape)
scene.rootNode.addChildNode(topBorderNode)
topBorderNode.physicsBody!.categoryBitMask = 0b001
topBorderNode.physicsBody!.collisionBitMask = 0b100
// Add physics to the dice
for dice in dices {
dice.physicsBody = SCNPhysicsBody.dynamicBody()
dice.physicsBody!.mass = 1.5
dice.physicsBody!.restitution = 0.0
dice.physicsBody!.friction = 0.8
dice.physicsBody!.damping = 0.1
dice.physicsBody!.categoryBitMask = 0b100
dice.physicsBody!.collisionBitMask = 0b001 | 0b010 | 0b100
}
// Add body to the numbertiles
for name in numberNames {
var numberNode = scene.rootNode.childNodeWithName(name, recursively: false)!
numberNode.physicsBody = SCNPhysicsBody.kinematicBody()
numberNode.physicsBody!.categoryBitMask = 0b001
numberNode.physicsBody!.collisionBitMask = 0b100
}
// add a tap, pan and longPress gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
let panGesture = UIPanGestureRecognizer(target: self, action: "handlePan:")
let longPressGesture = UILongPressGestureRecognizer(target: self, action:"handleLongPress:")
var gestureRecognizers = [AnyObject]()
gestureRecognizers.append(tapGesture)
gestureRecognizers.append(panGesture)
gestureRecognizers.append(longPressGesture)
if let existingGestureRecognizers = scnView.gestureRecognizers {
gestureRecognizers.extend(existingGestureRecognizers)
}
scnView.gestureRecognizers = gestureRecognizers
// initialize game
initGame()
}
As u can see I create 35 global variables and there are many lines (130!) of code in viewDidLoad. I guess this is why it takes so long to load. I need the variables later in multiple methods, so they cannot be changed to local variables.
I know it is probably bad coding, but it is my first attempt of creating a full working game, which is totally different and larger than many tutorials and courses I have followed. I am still learning..
Could you give me some advice on how to reduce the render time of the SCNView when the game is opened?
All help is very much appreciated!

Resources