What is Augmented Reality?
- Augmented reality is made up of the word “augment” which means to make something great by adding something to it.
- Augmented reality is used to add 2D or 3D objects to the live view using the device’s camera.
- Generally, Augmented Reality is used into indoor such as indoor path mapping, interior designing, airport, hospitals path mapping, games
- There are some popular applications which are using AR: LensKart, Pokemon GO, Real Strike and many more.
- You can also create many kinds of AR applications using the front or rear camera of the device.
- iPhone 6s and up devices with A9 chip and up devices support ARKit functionality. Please note, ARKit is not available to xCode Simulator.
What is ARNode?
- AR Node is used to add any objects on live view. It basically works on x-axis, y-axis and z-axis.
- We need to set all three axes for any object. Also, we can add multiple child objects for parent objects.
- For example, You’re creating a car game then we can add tyres, seats as a child of the parent node.
- For implementing AR into iOS. We need to import the ARKit package into the project.
In today’s demo, we are going to scan images and place objects on the screen. After that, we will fill colours on objects parts.
Let’s get started.
Step 1
Open Xcode -> Create New project -> Select options as mentioned in below image.
Step 2
Open Main. storyboard file, add sceneKit view, button, label to the ViewController and add constraints to it.
Step 3
Open ViewController.swift file and import below 2 libraries which are provided by apple default. After that, connect the scenekit with the outlet. Set delegate of sceneView inside viewDidLoad().
import ARKit
import SceneKit
@IBOutlet weak var sceneView: ARSCNView!
Step 4
Download object file from below mentioned link and add into app after that convert it to .scn file as mentioned below:
Step 5
Open Assets.xcassets -> Click on + from the bottom left corner as shown in below image. Add Robot image into AR Resources group and name it to Robot (It is case-sensitive).
Step 6
Create fade duration related variables.
let fadeDuration: TimeInterval = 0.3
let rotateDuration: TimeInterval = 5
let waitDuration: TimeInterval = 0.5
//MARK: create fade and spin action variable
lazy var fadeAndSpinAction: SCNAction = {
return .sequence([
.fadeIn(duration: fadeDuration),
.rotateBy(x: 0, y: 0, z: CGFloat.pi * 360 / 180, duration: rotateDuration),
.wait(duration: waitDuration),
])
}()
//MARK: create fade action variable
lazy var fadeAction: SCNAction = {
return .sequence([
.fadeOpacity(by: 0.8, duration: fadeDuration),
.wait(duration: waitDuration),
.fadeOut(duration: fadeDuration)
])
}()
//MARK: create SCNNode node type as robot node
lazy var robotNode: SCNNode = {
//create scene and replace robot.scn with your .scn filename
guard let scene = SCNScene(named: "robot.scn"),
//Add all child nodes of robot node
let node = scene.rootNode.childNode(withName: "robot", recursively: false) else { return SCNNode() }
let scaleFactor = 0.024
//all nodes added into this array
var nodeArray = scene.rootNode.childNodes
for childNode in nodeArray {
node.addChildNode(childNode as SCNNode)
}
node.scale = SCNVector3(scaleFactor, scaleFactor, scaleFactor)
node.pivot = SCNMatrix4MakeTranslation(0, 0, 0)
node.eulerAngles.x += -.pi / 2
//1. Get The Bounding Box Of The Node
let minimum = float3(node.boundingBox.min)
let maximum = float3(node.boundingBox.max)
//2. Set The Translation To Be Half Way Between The Vector
let translation = (maximum - minimum) * 0.5
//3. Set The Pivot
node.pivot = SCNMatrix4MakeTranslation(translation.x, translation.y, translation.z)
return node
}()
Step 7
Add tap gesture on scene view and call if from viewDidLoad().
//MARK: add tap gesture on the scene view
func registerGestureRecognizer() {
let tap = UITapGestureRecognizer(target: self, action: #selector(didTapped))
self.sceneView.addGestureRecognizer(tap)
}
Step 8
Configure lighting for scenview at the load time.
func configureLighting() {
sceneView.autoenablesDefaultLighting = true
sceneView.automaticallyUpdatesLighting = true
}
Step 9
Replace your viewDidLoad() function with below.
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
configureLighting()
registerGestureRecognizer()
}
Step 10
Add ARSCNViewDelegate to ViewController class.
extension ViewController: ARSCNViewDelegate {
//It renders image using camera ad gives name of the image
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
guard let imageAnchor = anchor as? ARImageAnchor,
let imageName = imageAnchor.referenceImage.name else { return }
// TODO: Overlay 3D Object
let overlayNode = self.getNode(withImageName: imageName)
overlayNode.opacity = 0
overlayNode.position.y = 0.2
overlayNode.geometry?.firstMaterial!.diffuse.contents = nil
let moveLoop = SCNAction.repeatForever(self.fadeAndSpinAction)
overlayNode.runAction(moveLoop)
node.addChildNode(overlayNode)
self.label.text = "Image detected: \"\(imageName)\""
}
}
func getPlaneNode(withReferenceImage image: ARReferenceImage) -> SCNNode {
let plane = SCNPlane(width: image.physicalSize.width,
height: image.physicalSize.height)
let node = SCNNode(geometry: plane)
return node
}
func getNode(withImageName name: String) -> SCNNode {
var node = SCNNode()
switch name {
case "Robot":
node = robotNode
default:
break
}
return node
}
}
Step 11
create UIColor extension to generate random colors and assign it to tapped nodes.
extension UIColor {
/**
* Example:
* self.backgroundColor = UIColor.random
*/
static var random: UIColor {
let r:CGFloat = .random(in: 0…1)
let g:CGFloat = .random(in: 0…1)
let b:CGFloat = .random(in: 0…1)
return UIColor(red: r, green: g, blue: b, alpha: 1)
}
}
Step 12
Get node name of tapped and fill color on that particular node
@objc func didTapped(sender: UITapGestureRecognizer) {
let location = sender.location(in: sceneView)
let results = sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])
print("Touched node name : \(results.first?.node.name)")
results.first?.node.geometry?.firstMaterial?.diffuse.contents = UIColor.random
results.first?.node.geometry?.firstMaterial?.specular.contents = UIColor.white
}
For more details regarding Object color change using ARKit, contact us.