Guest User

Untitled

a guest
Jan 18th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.76 KB | None | 0 0
  1. class Plane: SCNNode {
  2. var anchor :ARPlaneAnchor
  3. var planeGeometry :SCNPlane!
  4.  
  5. init(anchor :ARPlaneAnchor) {
  6. self.anchor = anchor
  7. super.init()
  8. setup()
  9. }
  10.  
  11. func update(anchor: ARPlaneAnchor) {
  12. self.planeGeometry.width = CGFloat(anchor.extent.x)
  13. self.planeGeometry.height = CGFloat(anchor.extent.z)
  14. self.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
  15. let planeNode = self.childNodes.first!
  16. planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
  17. }
  18.  
  19. private func setup() {
  20. //plane dimensions
  21. self.planeGeometry = SCNPlane(width: CGFloat(self.anchor.extent.x), height: CGFloat(self.anchor.extent.z))
  22. //plane material
  23. let material = SCNMaterial()
  24. material.diffuse.contents = UIImage(named: "tronGrid.png")
  25. self.planeGeometry.materials = [material]
  26. //plane geometry and physics
  27. let planeNode = SCNNode(geometry: self.planeGeometry)
  28. planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
  29. planeNode.physicsBody?.categoryBitMask = BodyType.plane.rawValue
  30. planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
  31. planeNode.transform = SCNMatrix4MakeRotation(Float(-Double.pi / 2.0), 1, 0, 0)
  32. //add plane node
  33. self.addChildNode(planeNode)
  34. }
  35.  
  36. enum BodyType: Int {
  37. case box = 1
  38. case pyramid = 2
  39. case plane = 3
  40. }
  41. class ViewController: UIViewController, ARSCNViewDelegate, SCNPhysicsContactDelegate {
  42. //outlets
  43. @IBOutlet var sceneView: ARSCNView!
  44. //globals
  45. var planes = [Plane]()
  46. var boxes = [SCNNode]()
  47. //life cycle
  48. override func viewDidLoad() {
  49. super.viewDidLoad()
  50. //set sceneView's frame
  51. self.sceneView = ARSCNView(frame: self.view.frame)
  52. //add debugging option for sceneView (show x, y , z coords)
  53. self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints, ARSCNDebugOptions.showWorldOrigin]
  54. //give lighting to the scene
  55. self.sceneView.autoenablesDefaultLighting = true
  56. //add subview to scene
  57. self.view.addSubview(self.sceneView)
  58. // Set the view's delegate
  59. sceneView.delegate = self
  60. //subscribe to physics contact delegate
  61. self.sceneView.scene.physicsWorld.contactDelegate = self
  62. //show statistics such as fps and timing information
  63. sceneView.showsStatistics = true
  64. //create new scene
  65. let scene = SCNScene()
  66. //set scene to view
  67. sceneView.scene = scene
  68. //setup recognizer to add scooter to scene
  69. let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
  70. sceneView.addGestureRecognizer(tapGestureRecognizer)
  71. }
  72. //MARK: helper funcs
  73. //private var boxStatus: BoxStatus = .notAdded
  74.  
  75. @objc func tapped(recognizer: UIGestureRecognizer) {
  76. let scnView = recognizer.view as! ARSCNView
  77. let touchLocation = recognizer.location(in: scnView)
  78. let touch = scnView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
  79. //take action if user touches box
  80. if !touch.isEmpty {
  81. guard let hitResult = touch.first else { return }
  82. addBox(hitResult: hitResult)
  83. }
  84. }
  85.  
  86. // private func nodeForScene(sceneName: String, nodeName: String) -> SCNNode? {
  87. // let scn = SCNScene(named: sceneName)!
  88. // return scn.rootNode.childNode(withName: nodeName, recursively: true)
  89. // }
  90.  
  91. private func addBox(hitResult: ARHitTestResult) {
  92. let boxGeometry = SCNBox(width: 0.1,
  93. height: 0.1,
  94. length: 0.1,
  95. chamferRadius: 0)
  96. let material = SCNMaterial()
  97. material.diffuse.contents = UIColor(red: .random(),
  98. green: .random(),
  99. blue: .random(),
  100. alpha: 1.0)
  101. boxGeometry.materials = [material]
  102. let boxNode = SCNNode(geometry: boxGeometry)
  103. //adding physics body, a box already has a shape, so nil is fine
  104. boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
  105. //set bitMask on boxNode, enabling objects with diff categoryBitMasks to collide w/ each other
  106. boxNode.physicsBody?.categoryBitMask = BodyType.plane.rawValue | BodyType.box.rawValue
  107. boxNode.position = SCNVector3(hitResult.worldTransform.columns.3.x,
  108. hitResult.worldTransform.columns.3.y + 0.3,
  109. hitResult.worldTransform.columns.3.z)
  110. self.sceneView.scene.rootNode.addChildNode(boxNode)
  111. }
  112.  
  113. override func viewWillAppear(_ animated: Bool) {
  114. super.viewWillAppear(animated)
  115. let configuration = ARWorldTrackingConfiguration()
  116. configuration.planeDetection = .horizontal
  117. //track objects in ARWorld and start session
  118. sceneView.session.run(configuration)
  119. }
  120. //MARK: - ARSCNViewDelegate
  121. func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
  122. //if no anchor found, don't render anything!
  123. if !(anchor is ARPlaneAnchor) {
  124. return
  125. }
  126. DispatchQueue.main.async {
  127. //add plane to scene
  128. let plane = Plane(anchor: anchor as! ARPlaneAnchor)
  129. self.planes.append(plane)
  130. node.addChildNode(plane)
  131. //add initial scene object
  132. let pyramidGeometry = SCNPyramid(width: CGFloat(plane.planeGeometry.width / 8), height: plane.planeGeometry.height / 8, length: plane.planeGeometry.height / 8)
  133. pyramidGeometry.firstMaterial?.diffuse.contents = UIColor.white
  134. let pyramidNode = SCNNode(geometry: pyramidGeometry)
  135. pyramidNode.name = "pyramid"
  136. pyramidNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
  137. pyramidNode.physicsBody?.categoryBitMask = BodyType.pyramid.rawValue | BodyType.plane.rawValue
  138. pyramidNode.physicsBody?.contactTestBitMask = BodyType.box.rawValue
  139. pyramidNode.position = SCNVector3(-(plane.planeGeometry.width) / 3, 0, plane.planeGeometry.height / 3)
  140. node.addChildNode(pyramidNode)
  141. }
  142. }
  143. func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
  144. let plane = self.planes.filter {
  145. plane in return plane.anchor.identifier == anchor.identifier
  146. }.first
  147.  
  148. if plane == nil {
  149. return
  150. }
  151.  
  152. plane?.update(anchor: anchor as! ARPlaneAnchor)
  153. }
  154. override func viewWillDisappear(_ animated: Bool) {
  155. super.viewWillDisappear(animated)
  156. //pause session
  157. sceneView.session.pause()
  158. }
  159. }
Add Comment
Please, Sign In to add comment