-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathARView.swift
193 lines (137 loc) · 6.04 KB
/
ARView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//
// ARView.swift
// HUGO
//
// Created by Claudia Eng on 11/11/19.
// Copyright © 2019 Claudia Eng. All rights reserved.
//
import Foundation
import SwiftUI
import SceneKit
import ARKit
import UIKit
//missing
// sceneView.session.pause() on dissapear
struct ARView: View {
var body: some View {
ARViewContainer().edgesIgnoringSafeArea(.all)
}
}
struct ARViewContainer: UIViewRepresentable {
let sceneView = ARSCNView(frame: .zero)
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> ARSCNView {
//good
sceneView.showsStatistics = true
sceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints
let scene = SCNScene()
sceneView.scene = scene
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .vertical
let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator,
action: #selector(Coordinator.tapped))
sceneView.addGestureRecognizer(gestureRecognizer)
sceneView.session.run(configuration)
sceneView.delegate = context.coordinator
return sceneView
}
func updateUIView(_ uiView: ARSCNView, context: Context) {
print()
}
class Coordinator: NSObject, ARSCNViewDelegate {
var arViewContainer: ARViewContainer
var grids = [Grid]()
init(_ arViewContainer: ARViewContainer) {
self.arViewContainer = arViewContainer
}
func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
}
@objc func tapped(gesture: UITapGestureRecognizer) {
// Get 2D position of touch event on screen
let touchPosition = gesture.location(in: arViewContainer.sceneView)
// Translate those 2D points to 3D points using hitTest (existing plane)
let hitTestResults = arViewContainer.sceneView.hitTest(touchPosition, types: .existingPlaneUsingExtent)
// Get hitTest results and ensure that the hitTest corresponds to a grid that has been placed on a wall
guard let hitTest = hitTestResults.first, let anchor = hitTest.anchor as? ARPlaneAnchor, let gridIndex = grids.firstIndex(where: { $0.anchor == anchor }) else {
return
}
addPainting(hitTest, grids[gridIndex])
}
func addPainting(_ hitResult: ARHitTestResult, _ grid: Grid) {
// 1.
let planeGeometry = SCNPlane(width: 0.2, height: 0.35)
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "mona-lisa")
planeGeometry.materials = [material]
// 2.
let paintingNode = SCNNode(geometry: planeGeometry)
paintingNode.transform = SCNMatrix4(hitResult.anchor!.transform)
paintingNode.eulerAngles = SCNVector3(paintingNode.eulerAngles.x + (-Float.pi / 2), paintingNode.eulerAngles.y, paintingNode.eulerAngles.z)
paintingNode.position = SCNVector3(hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y, hitResult.worldTransform.columns.3.z)
arViewContainer.sceneView.scene.rootNode.addChildNode(paintingNode)
grid.removeFromParentNode()
}
//good
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor, planeAnchor.alignment == .vertical else { return }
let grid = Grid(anchor: planeAnchor)
self.grids.append(grid)
node.addChildNode(grid)
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor, planeAnchor.alignment == .vertical else { return }
let grid = self.grids.filter { grid in
return grid.anchor.identifier == planeAnchor.identifier
}.first
guard let foundGrid = grid else {
return
}
foundGrid.update(anchor: planeAnchor)
}
//good
}
}
struct ARView_Previews: PreviewProvider {
static var previews: some View {
ARView()
}
}
class Grid : SCNNode {
var anchor: ARPlaneAnchor
var planeGeometry: SCNPlane!
init(anchor: ARPlaneAnchor) {
self.anchor = anchor
super.init()
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(anchor: ARPlaneAnchor) {
planeGeometry.width = CGFloat(anchor.extent.x);
planeGeometry.height = CGFloat(anchor.extent.z);
position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
let planeNode = self.childNodes.first!
planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
}
private func setup() {
planeGeometry = SCNPlane(width: CGFloat(self.anchor.extent.x), height: CGFloat(self.anchor.extent.z))
let material = SCNMaterial()
material.diffuse.contents = UIImage(named:"overlay_grid.png")
planeGeometry.materials = [material]
let planeNode = SCNNode(geometry: self.planeGeometry)
planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
planeNode.physicsBody?.categoryBitMask = 2
planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
planeNode.transform = SCNMatrix4MakeRotation(Float(-Double.pi / 2.0), 1.0, 0.0, 0.0);
addChildNode(planeNode)
}
}