Skip to content

Instantly share code, notes, and snippets.

@jungchris
Last active September 17, 2020 21:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jungchris/a2c756d41b011e4045101b9f58ee0bd1 to your computer and use it in GitHub Desktop.
Save jungchris/a2c756d41b011e4045101b9f58ee0bd1 to your computer and use it in GitHub Desktop.
Create a horizontal plane detector and replace the surface with an image
import UIKit
import ARKit
import SceneKit
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet weak var sceneView: ARSCNView!
let configuration = ARWorldTrackingConfiguration()
override func viewDidLoad() {
super.viewDidLoad()
// set delegate so renderer fn gets called
sceneView.delegate = self
// set debug options using an array
sceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin, ARSCNDebugOptions.showFeaturePoints]
// type of plane detection
configuration.planeDetection = .vertical
// run, requests camera access first run
sceneView.session.run(configuration)
}
// create surface, in this case grass aka "turf", but could be anything depending on image
func createTurf(planeAnchor: ARPlaneAnchor) -> SCNNode {
// create scene node
let turfNode = SCNNode(geometry: SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z)))
// now set node properties such as material and position
turfNode.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "ocean")
turfNode.geometry?.firstMaterial?.isDoubleSided = true
turfNode.position = SCNVector3(planeAnchor.center.x, planeAnchor.center.y, planeAnchor.center.z)
// use extension to rotate 90 degrees about x axis <--x-->
turfNode.eulerAngles = SCNVector3(-90.degreesToRadians, 0, 0)
return turfNode
}
// This delegate fires when an anchor is added whenever an ARAnchor was added to the sceneview. An anchor encodes position, size and orientation of something ... the surface in this case.
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
print("New surface detected")
// notice that we {return} early if we don't have an anchor
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
// ... otherwise we proceed creating and adding the scene node
let turfNode = createTurf(planeAnchor: planeAnchor)
node.addChildNode(turfNode)
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
print("Surface updated")
guard let planeAnchor = anchor as? ARPlaneAnchor else {return}
node.enumerateChildNodes { (childNode, _) in
childNode.removeFromParentNode()
}
let turfNode = createTurf(planeAnchor: planeAnchor)
node.addChildNode(turfNode)
}
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
print("Surface anchor removed")
node.enumerateChildNodes { (childNode, _) in
childNode.removeFromParentNode()
}
}
}
extension Int {
var degreesToRadians: Double { return Double(self) * .pi/180 }
}
@jungchris
Copy link
Author

Made a few edits to update the code and provide better comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment