Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ARKit Basics w/Physics
//-- 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