Created
December 24, 2017 03:55
-
-
Save adilanchian/ca77adbfab7820d1f5cc10a4f74fc156 to your computer and use it in GitHub Desktop.
ARKit Basics w/Physics
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//-- Center Middle Overlay --// | |
@IBOutlet weak var centerOverlayView: UIView! | |
//-- AR Properties --// | |
@IBOutlet weak var arSceneView: ARSCNView! | |
let useARView = true | |
var screenCenter: CGPoint = CGPoint() | |
var planeAnchors = [ARPlaneAnchor]() | |
//-- Scenekit Properties --// | |
let imageScene: SCNScene! = SCNScene() | |
//-- Image Properties --// | |
var photosNearbyRaw: [UIImage]? = [UIImage]() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
if useARView { | |
self.arSceneView.delegate = self | |
self.arSceneView.showsStatistics = true | |
// Tap gesture on circle view // | |
let circleTapGesture = UITapGestureRecognizer(target: self, action: #selector(self.placeImageNode(sender:))) | |
self.centerOverlayView.addGestureRecognizer(circleTapGesture) | |
// Get Center Of AR View // | |
self.screenCenter = CGPoint(x: self.arSceneView.bounds.midX, y: self.arSceneView.bounds.midY) | |
} | |
// Setup scene // | |
self.sceneSetup() | |
} | |
override func viewWillDisappear(_ animated: Bool) { | |
super.viewWillDisappear(animated) | |
if useARView { | |
// Pause the view's session | |
self.arSceneView.session.pause() | |
} | |
} | |
//-- Scenekit --// | |
func sceneSetup() { | |
// Setup camera // | |
if !useARView { | |
let camera = SCNCamera() | |
let cameraNode = SCNNode() | |
cameraNode.camera = camera | |
cameraNode.camera?.name = "cameraNode" | |
cameraNode.position = SCNVector3(x: 0, y: 0, z: 75.0) | |
imageScene.rootNode.addChildNode(cameraNode) | |
// Set imageScene // | |
self.sceneView.scene = imageScene | |
self.sceneView.allowsCameraControl = true | |
} else { | |
self.arSceneView.scene = self.imageScene | |
} | |
} | |
//-- ARKit --// | |
// On center image tap // | |
@objc func placeImageNode(sender: UITapGestureRecognizer?) { | |
// Animate button tap // | |
UIView.animate(withDuration: 0.3, animations: { | |
self.centerOverlayView.backgroundColor = UIColor.darkGray | |
}) { (didFinish) in | |
if didFinish { | |
self.centerOverlayView.backgroundColor = UIColor.clear | |
} | |
} | |
/* | |
1. Get index from collection view | |
2. Create node, and place | |
*/ | |
print("Getting ready to render image...") | |
// 1. Get index from collection view // | |
if let currentIndex = self.currentIndexPath?.row { | |
print("Current index row @ index: \(currentIndex)") | |
// 2. Create node, and place // | |
if self.planeAnchors.count > 0 { | |
print("There are planes for hit tests!") | |
let planeTestResults = self.arSceneView.hitTest(self.screenCenter, types: [.existingPlaneUsingExtent]) | |
if planeTestResults.count > 0 { | |
print("We got our hit results!") | |
let result = planeTestResults.first! as ARHitTestResult | |
// Create node to add to scene // | |
let imageBox = SCNBox(width: 0.02, height: 0.5, length: 0.5, chamferRadius: 0) | |
let imageMatieral = SCNMaterial() | |
imageMatieral.diffuse.contents = self.photosNearbyRaw?[currentIndex] | |
imageBox.materials = [imageMatieral] | |
imageBox.firstMaterial?.isDoubleSided = true | |
// Force // | |
let imageNode = SCNNode(geometry: imageBox) | |
imageNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil) | |
imageNode.physicsBody?.applyForce(SCNVector3(x: 0.0, y: 1.0, z: 0.0), asImpulse: true) | |
imageNode.physicsBody?.mass = 5.0 | |
imageNode.position = SCNVector3(x: result.worldTransform.columns.3.x, y: result.worldTransform.columns.3.y + 1.0, z: result.worldTransform.columns.3.z) | |
self.arSceneView.scene.rootNode.addChildNode(imageNode) | |
} | |
} | |
} else { | |
print("IndexPath is not available.") | |
} | |
} | |
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { | |
print("In didAdd delegate") | |
guard let planeAnchor = anchor as? ARPlaneAnchor else { | |
print("This was not a ARPlaneAnchor") | |
return | |
} | |
// Create plane to visualize plane anchor // | |
let planeBox = SCNBox(width: CGFloat(planeAnchor.extent.x), height: 0.01, length: CGFloat(planeAnchor.extent.z), chamferRadius: 0) | |
let planeNode = SCNNode(geometry: planeBox) | |
// Physics // | |
planeNode.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(node: planeNode, options: nil)) | |
planeNode.simdPosition = float3(planeAnchor.center.x, 0.01 / 2, planeAnchor.center.z) | |
planeNode.opacity = 0.25 | |
node.addChildNode(planeNode) | |
// Add anchor to anchor array // | |
self.planeAnchors.append(planeAnchor) | |
} | |
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { | |
guard let planeAnchor = anchor as? ARPlaneAnchor, | |
let planeNode = node.childNodes.first, | |
let plane = planeNode.geometry as? SCNBox | |
else { return } | |
planeNode.simdPosition = float3(planeAnchor.center.x, 0.01 / 2, planeAnchor.center.z) | |
// Physics // | |
planeNode.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(node: planeNode, options: nil)) | |
planeNode.simdPosition = float3(planeAnchor.center.x, 0.01 / 2, planeAnchor.center.z) | |
plane.width = CGFloat(planeAnchor.extent.x) | |
plane.height = 0.01 | |
plane.length = CGFloat(planeAnchor.extent.z) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment