Skip to content

Instantly share code, notes, and snippets.

@VAnsimov
Created December 18, 2020 08:51
Show Gist options
  • Save VAnsimov/08e0918445cb9f750abd6b39a4003e50 to your computer and use it in GitHub Desktop.
Save VAnsimov/08e0918445cb9f750abd6b39a4003e50 to your computer and use it in GitHub Desktop.
import Foundation
import ARKit
extension ARPlaneAnchor {
@discardableResult
func addPlaneNode(on node: SCNNode, geometry: SCNGeometry, contents: Any) -> SCNNode {
guard let material = geometry.materials.first else { fatalError() }
if let program = contents as? SCNProgram {
material.program = program
} else {
material.diffuse.contents = contents
}
let planeNode = SCNNode(geometry: geometry)
DispatchQueue.main.async(execute: {
node.addChildNode(planeNode)
})
return planeNode
}
func addPlaneNode(on node: SCNNode, contents: Any) {
let geometry = SCNPlane(width: CGFloat(extent.x), height: CGFloat(extent.z))
let planeNode = addPlaneNode(on: node, geometry: geometry, contents: contents)
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2.0, 1, 0, 0)
}
func findPlaneNode(on node: SCNNode) -> SCNNode? {
for childNode in node.childNodes {
if childNode.geometry as? SCNPlane != nil {
return childNode
}
}
return nil
}
func findShapedPlaneNode(on node: SCNNode) -> SCNNode? {
for childNode in node.childNodes {
if childNode.geometry as? ARSCNPlaneGeometry != nil {
return childNode
}
}
return nil
}
@available(iOS 11.3, *)
func findPlaneGeometryNode(on node: SCNNode) -> SCNNode? {
for childNode in node.childNodes {
if childNode.geometry as? ARSCNPlaneGeometry != nil {
return childNode
}
}
return nil
}
@available(iOS 11.3, *)
func updatePlaneGeometryNode(on node: SCNNode) {
DispatchQueue.main.async(execute: {
guard let planeGeometry = self.findPlaneGeometryNode(on: node)?.geometry as? ARSCNPlaneGeometry else { return }
planeGeometry.update(from: self.geometry)
})
}
func updatePlaneNode(on node: SCNNode) {
DispatchQueue.main.async(execute: {
guard let plane = self.findPlaneNode(on: node)?.geometry as? SCNPlane else { return }
guard !PlaneSizeEqualToExtent(plane: plane, extent: self.extent) else { return }
plane.width = CGFloat(self.extent.x)
plane.height = CGFloat(self.extent.z)
})
}
}
fileprivate func PlaneSizeEqualToExtent(plane: SCNPlane, extent: vector_float3) -> Bool {
if plane.width != CGFloat(extent.x) || plane.height != CGFloat(extent.z) {
return false
} else {
return true
}
}
class PlaneDetectionViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.scene = SCNScene()
sceneView.debugOptions = [SCNDebugOptions.showFeaturePoints]
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else { fatalError() }
planeAnchor.addPlaneNode(on: node, contents: UIColor.arBlue.withAlphaComponent(0.3))
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else { fatalError() }
planeAnchor.updatePlaneNode(on: node)
}
}
import ARKit
class ShapedPlaneViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
private let device = MTLCreateSystemDefaultDevice()!
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.scene = SCNScene()
sceneView.debugOptions = [SCNDebugOptions.showFeaturePoints, SCNDebugOptions.showWireframe]
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = [.vertical, .horizontal]
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
print("\(self.classForCoder)/" + #function + ", anchor id: \(anchor.identifier)")
guard let planeAnchor = anchor as? ARPlaneAnchor else {fatalError()}
let planeGeometry = ARSCNPlaneGeometry(device: device)!
planeGeometry.update(from: planeAnchor.geometry)
let color = planeAnchor.alignment == .horizontal ? UIColor.arBlue : UIColor.green
planeAnchor.addPlaneNode(on: node, geometry: planeGeometry, contents: color.withAlphaComponent(0.3))
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else {fatalError()}
if let planeGeometry = planeAnchor.findShapedPlaneNode(on: node)?.geometry as? ARSCNPlaneGeometry {
planeGeometry.update(from: planeAnchor.geometry)
}
}
func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
print("\(self.classForCoder)/" + #function)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment