I am a new iOS programming. I want to build an application which allow user to click on specific object that has been shown on the screen. I am using addGestureRecognizer
to the object that has been shown in order to identify if user has been clicked then i just want to add another object to the screen.
Here is what i done so far
objpizza = make2dNode(image:#imageLiteral(resourceName: "pizza"),width: 0.07,height: 0.07)
objpizza.position = SCNVector3(0,0,-0.2)
objpizza.name = "none"
self.arView.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(selectObject)))
arView.scene.rootNode.addChildNode(objpizza)
Here is make2dNode
function just adjust the object
func make2dNode(image: UIImage, width: CGFloat = 0.1, height: CGFloat = 0.1) -> SCNNode {
let plane = SCNPlane(width: width, height: height)
plane.firstMaterial!.diffuse.contents = image
let node = SCNNode(geometry: plane)
node.constraints = [SCNBillboardConstraint()]
return node
}
Here is function that never called when i implemented in self.arView.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(selectObject)))
@objc func selectObject() {
print("Image has been selected")
}
Detecting a touch on an SCNNode
requires more than simply adding a UITapGestureRecogniser
to your view.
In order to detect which SCNNode you have touched you need to make use of an SCNHitTest (in combination with your gestureRecognizer) which is:
The process of finding elements of a scene located at a specified point, or along a specified line segment (or ray).
An SCNHitTest
looks for:
SCNGeometry objects along the ray you specify. For each intersection between the ray and and a geometry, SceneKit creates a hit-test result to provide information about both the SCNNode object containing the geometry and the location of the intersection on the geometry’s surface.
Ok great you might be thinking, but how does this actually work in my case?
Well, lets begin by creating an SCNNode with an SCNSphere Geometry and adding it to our scene.
//1. Create An SCNNode With An SCNSphere Geometry
let nodeOneGeometry = SCNSphere(radius: 0.2)
//2. Set It's Colour To Cyan
nodeOneGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
//3. Assign The Geometry To The Node
nodeOne = SCNNode(geometry: nodeOneGeometry)
//4. Assign A Name For Our Node
nodeOne.name = "Node One"
//5. Position It & Add It To Our ARSCNView
nodeOne.position = SCNVector3(0, 0, -1.5)
augmentedRealityView.scene.rootNode.addChildNode(nodeOne)
You will note here, that I have assigned a name to our SCNNode, this makes keeping track of it (e.g. identifying it through a hitTest) much easier.
Now we have added our SCNNode to the hierachy, lets create a UITapGestureRecognizer
like so:
//1. Create A UITapGestureRecognizer & Add It To Our MainView
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(checkNodeHit(_:)))
tapGesture.numberOfTapsRequired = 1
self.view.addGestureRecognizer(tapGesture)
Now we have this all setup we need to create our checkNodeHit function will detect which node the user has tapped on:
/// Runs An SCNHitTest To Check If An SCNNode Has Been Hit
///
/// - Parameter gesture: UITapGestureRecognizer
@objc func checkNodeHit(_ gesture: UITapGestureRecognizer){
//1. Get The Current Touch Location In The View
let currentTouchLocation = gesture.location(in: self.augmentedRealityView)
//2. Perform An SCNHitTest To Determine If We Have Hit An SCNNode
guard let hitTestNode = self.augmentedRealityView.hitTest(currentTouchLocation, options: nil).first?.node else { return }
if hitTestNode.name == "Node One"{
print("The User Has Successfuly Tapped On \(hitTestNode.name!)")
}
}
Now if you wanted to place an SCNNode where the user tapped you would have to use an ARSCNHitTest instead to do so which provides:
Information about a real-world surface found by examining a point in the device camera view of an AR session.
By performing this we are then able to use the worldTransform
property of our result to place virtual content at that location.
For your information the worldTransform is:
The position and orientation of the hit test result relative to the world coordinate system.
Positioning in ARKit can easily be visualised like so:
Again lets look at how we could use this to place a virtual object:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//1. Get The Current Touch Location In Our ARSCNView & Perform An ARSCNHitTest For Any Viable Feature Points
guard let currentTouchLocation = touches.first?.location(in: self.augmentedRealityView),
let hitTest = self.augmentedRealityView.hitTest(currentTouchLocation, types: .featurePoint).first else { return }
//2. Get The World Transform From The HitTest & Get The Positional Data From The Matrix (3rd Column)
let worldPositionFromTouch = hitTest.worldTransform.columns.3
//3. Create An SCNNode At The Touch Location
let boxNode = SCNNode()
let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
boxGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
boxNode.geometry = boxGeometry
boxNode.position = SCNVector3(worldPositionFromTouch.x, worldPositionFromTouch.y, worldPositionFromTouch.z)
//4. Add It To The Scene Hierachy
self.augmentedRealityView.scene.rootNode.addChildNode(boxNode)
}
Hope it helps...
You need to implement
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
arView.addGestureRecognizer(tapGesture)
For function identifies if user has been clicked
@obj func didTap(_ gesture: UITabGestureRecognizer){
object2 = make2Node(image: nameOfimage, width: 0.07, height: 0.07)
object2.position = SCNVector(0,0,0.2)
arView.scene.rootNode.addChildNode(object2)
Enjoy coding bro.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With