Last active
September 17, 2020 21:47
-
-
Save jungchris/a2c756d41b011e4045101b9f58ee0bd1 to your computer and use it in GitHub Desktop.
Create a horizontal plane detector and replace the surface with an image
This file contains 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
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 } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Made a few edits to update the code and provide better comments