Scnnode and Firebase

Swift 4 Load 3D Models from Firebase

I solved this problem by downloading the 3D Object from firebase into the devices document folder.
So when I need the 3D-object I create a reference to the downloaded 3D-Object

write To Directory: (where modelPath is the storage.child('your path') in firebase)

   let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let tempDirectory = URL.init(fileURLWithPath: paths, isDirectory: true)
let targetUrl = tempDirectory.appendingPathComponent("ship.scn")
modelPath.write(toFile: targetUrl) { (url, error) in
if error != nil {
print("ERROR: \(error!)")
}else{
print("modelPath.write OKAY")
}
}

load 3D file from directory:

let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let tempDirectory = URL.init(fileURLWithPath: paths, isDirectory: true)
let targetUrl = tempDirectory.appendingPathComponent("\ship.scn")
var sceneForNode: SCNScene? = nil
do {
// load the 3D-Model node from directory path
sceneForNode = try SCNScene(url: targetUrl, options: nil)
}catch{
print(error)
}
// create node to display on scene
let node: SCNNode? = sceneForNode?.rootNode.childNode(withName: "ship", recursively: true)

How to add a cube in the center of the screen, and so that it never leaves?

Here is an update to your code that ensure's the box is always at the center of the screen. Once the code detects a plane, it set's the box's parent as the plane anchor.

This is all very primitive, but should help you. If you want the node to float in the center of the screen, uncomment the SCNTransactions within the willRenderScene callback. If you want the box to always face the user, you can add a lookAtConstraint

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

@IBOutlet var sceneView: ARSCNView!
var boxNode: SCNNode? // keep a reference to the cube

override func viewDidLoad() {
super.viewDidLoad()

let scene = SCNScene()

let boxNode = createBox()
scene.rootNode.addChildNode(boxNode)
self.boxNode = boxNode

sceneView.scene = scene

//------------------------------------
// Set the view's delegate
sceneView.delegate = self

// Show statistics such as fps and timing information
sceneView.showsStatistics = true

// Set the scene to the view
sceneView.scene = scene
}

func createBox() -> SCNNode {
let boxGeometry = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)

let material = SCNMaterial()
material.diffuse.contents = UIColor.blue
material.specular.contents = UIColor(white: 0.6, alpha: 1.0)

let boxNode = SCNNode(geometry: boxGeometry)
boxNode.geometry?.materials = [material]

return boxNode;
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal

// Run the view's session
sceneView.session.run(configuration)
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

// Pause the view's session
sceneView.session.pause()
}

// on willRender update the cube's position.
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
// get camera translation and rotation
guard let pointOfView = sceneView.pointOfView else { return }
let transform = pointOfView.transform // transformation matrix
let orientation = SCNVector3(-transform.m31, -transform.m32, -transform.m33) // camera rotation
let location = SCNVector3(transform.m41, transform.m42, transform.m43) // camera translation

let currentPostionOfCamera = orientation + location
// SCNTransaction.begin()
if let boxNode = self.boxNode {
boxNode.position = currentPostionOfCamera
}
// SCNTransaction.commit()
}

// detect plances
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

guard anchor is ARPlaneAnchor else { return }
if let boxNode = self.boxNode {
let newBoxNode = createBox() // create a new node for the center of the screen
self.boxNode = newBoxNode
SCNTransaction.begin()
boxNode.removeFromParentNode()
node.addChildNode(boxNode) // set the current box to the plane.
sceneView.scene.rootNode.addChildNode(newBoxNode) // add the new box node to the scene
SCNTransaction.commit()
}

}
}

extension SCNVector3 {
static func + (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
}
}

SceneKit Fully Stop Simulation from Running at Instant?

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 Topics



Leave a reply



Submit