13 Mar 2021
iOS - hello ar world!
Notes from Beginning ARKit- Hello Augmented World!
How to Create a Sphere at Origin
/// Creates a blue sphere with 5 centimeters radius at the origin
/// It rotates 360 around y-axis and completes a rotation in 8 seconds
func drawSphereAtOrigin() -> SCNNode {
let sphere = SCNNode(geometry: SCNSphere(radius: 0.05))
// sets the sphere to a flat blue - diffuse = matte
sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
// sphere's origin is at (0,0,0)
sphere.position = SCNVector3(0, 0, 0)
/// rotate (360 degrees around its y-axis) the Sphere in 8 seconds once at the beginning of AR session
let rotateAction = SCNAction.rotate(by: 360.degreeToRadians(), around: SCNVector3(0, 1, 0), duration: 8)
sphere.runAction(rotateAction)
return sphere
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Run the view's session
sceneView.session.run(configuration)
let sphere = drawSphereAtOrigin()
sceneView.scene.rootNode.addChildNode(sphere)
}
extension Int {
/// Converts the Int in degrees to radians in CGFloat
/// - Returns: Radian in CGFloat
func degreeToRadians() -> CGFloat {
return CGFloat(self) * CGFloat.pi / 180.0
}
}
How to Create an Oribiting Ship around Earth
func drawOrbitingShip() -> SCNNode {
// grab the ship scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// extract the ship object from the scene
let ship = (scene.rootNode.childNode(withName: "ship", recursively: false))!
// ship is 1 meter to right of origin
ship.position = SCNVector3(1, 0, 0)
// rotates the ship about the y-axis, so it's facing the same direction as the Earth's rotation
ship.eulerAngles = SCNVector3(0, 180.degreeToRadians(), 0)
// scale it down to 1/3 of size since it's large relative to other shapes
ship.scale = SCNVector3(0.3, 0.3, 0.3)
return ship
}
func drawSphereAtOriginWithImages() -> SCNNode {
let sphere = SCNNode(geometry: SCNSphere(radius: 0.05))
// sets the sphere to use earth image
sphere.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "earth")
// sets the sphere to use yellow shine
sphere.geometry?.firstMaterial?.specular.contents = UIColor.yellow
// sphere's origin is at (0,0,0)
sphere.position = SCNVector3(0, 0, 0)
/// rotate (360 degrees around its y-axis) the Sphere in 8 seconds once at the beginning of AR session
let rotateAction = SCNAction.rotate(by: 360.degreeToRadians(), around: SCNVector3(0, 1, 0), duration: 8)
/// repeat the rotation
let rotateForeverAction = SCNAction.repeatForever(rotateAction)
sphere.runAction(rotateForeverAction)
return sphere
}
// How to Use It
let sphere = drawSphereAtOriginWithImages()
sceneView.scene.rootNode.addChildNode(sphere)
sphere.addChildNode(drawOrbitingShip())
How to Create a Box at 12:00 High
func drawBoxAt1200High() -> SCNNode {
let box = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.0))
// sets the sphere to a flat white - diffuse = matte
box.geometry?.firstMaterial?.diffuse.contents = UIColor.orange
// sets the sphere to a shinyh white - specular = shine
box.geometry?.firstMaterial?.specular.contents = UIColor.white
// 20 centimeters above origin & 30 centimeters behind origin
box.position = SCNVector3(0, 0.2, -0.3)
return box
}
// How to Use It
sceneView.scene.rootNode.addChildNode(drawBoxAt1200High())
How to Create a Pyramid at 6:00 Low
/// Challenge: Draw a pyramid
/// 10 centimeter high, 10 centimeter wide, 10 centimeter deep
/// green with red highlights
/// at 6'clock - 30 centimeters in front origin and 20 centimeters below origin
func drawPyramidAt600Low() -> SCNNode {
let pyramid = SCNNode(geometry: SCNPyramid(width: 0.10, height: 0.10, length: 0.10))
pyramid.geometry?.firstMaterial?.diffuse.contents = UIColor.green
pyramid.geometry?.firstMaterial?.specular.contents = UIColor.red
// 20 centimeters below origin & 30 centimeters in front origin
pyramid.position = SCNVector3(0, -0.20, 0.30)
return pyramid
}
// How to Use It
sceneView.scene.rootNode.addChildNode(drawPyramidAt600Low())
How to Draw a Cat on a Plane at 9:00
/// Challenge: Draws plane with a cat image on its surface
/// 10 centimeter high, 10 centimeter wide
/// 20 centimeters to the left of origin
func drawCatOnAPlaneAt900() -> SCNNode {
let plane = SCNNode(geometry: SCNPlane(width: 0.10, height: 0.10))
plane.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "cat")
plane.geometry?.firstMaterial?.isDoubleSided = true
// sets the plane at centimeters to the left of origin
plane.position = SCNVector3(-0.20, 0, 0)
return plane
}
// How to Use It
sceneView.scene.rootNode.addChildNode(drawCatOnAPlaneAt900())
How to Tilt A Cat
/// Challenge: Draws plane with a cat image on its surface
/// 10 centimeter high, 10 centimeter wide
/// 20 centimeters to the left of origin
/// 45 degrees clockwise around x axis
/// 20 degrees counterclockwise around y axis
/// 45 degrees counterclockwise around z axis
func tiltTheCat() -> SCNNode {
let plane = SCNNode(geometry: SCNPlane(width: 0.10, height: 0.10))
plane.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "cat")
plane.geometry?.firstMaterial?.isDoubleSided = true
// sets the plane at centimeters to the left of origin
plane.position = SCNVector3(-0.20, 0, 0)
// 45 degrees clockwise around x axis, 20 degrees counterclockwise around y axis, 45 degrees counterclockwise around z axis
plane.eulerAngles = SCNVector3(-45.degreeToRadians(), 20.degreeToRadians(), 45.degreeToRadians())
return plane
}
// How to Use It
sceneView.scene.rootNode.addChildNode(tiltTheCat())
How to Draw a Torus
/// Draws a Torus (doughnut) at 3 o'clock
/// Ring Radius = 5 centimeters
/// Pipe Radius = 3 centimeters
/// 20 centimeters to the left of origin
/// 45 degree angle
func drawTorusAt300() -> SCNNode {
let torus = SCNNode(geometry: SCNTorus(ringRadius: 0.05, pipeRadius: 0.03))
torus.geometry?.firstMaterial?.diffuse.contents = UIColor.red
torus.geometry?.firstMaterial?.specular.contents = UIColor.white
torus.position = SCNVector3(0.20, 0, 0)
// sets the z axis to a 45 degree angle
torus.eulerAngles = SCNVector3(0, 0, 45.degreeToRadians())
return torus
}
// How to Use It
sceneView.scene.rootNode.addChildNode(drawTorusAt300())
Entire File
//
// ViewController.swift
// HelloARWorld
//
// Created by Jess Lê on 3/13/21.
//
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// activates debugging features
sceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin,
ARSCNDebugOptions.showFeaturePoints]
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Run the view's session
sceneView.session.run(configuration)
let sphere = drawSphereAtOriginWithImages()
sceneView.scene.rootNode.addChildNode(sphere)
sphere.addChildNode(drawOrbitingShip())
sceneView.scene.rootNode.addChildNode(drawBoxAt1200High())
sceneView.scene.rootNode.addChildNode(drawPyramidAt600Low())
sceneView.scene.rootNode.addChildNode(drawTorusAt300())
// sceneView.scene.rootNode.addChildNode(drawCatOnAPlaneAt900())
sceneView.scene.rootNode.addChildNode(tiltTheCat())
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func drawSphereAtOrigin() -> SCNNode {
let sphere = SCNNode(geometry: SCNSphere(radius: 0.05))
// sets the sphere to a flat blue - diffuse = matte
sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
// sphere's origin is at (0,0,0)
sphere.position = SCNVector3(0, 0, 0)
/// rotate (360 degrees around its y-axis) the Sphere in 8 seconds once at the beginning of AR session
let rotateAction = SCNAction.rotate(by: 360.degreeToRadians(), around: SCNVector3(0, 1, 0), duration: 8)
sphere.runAction(rotateAction)
return sphere
}
func drawOrbitingShip() -> SCNNode {
// grab the ship scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// extract the ship object from the scene
let ship = (scene.rootNode.childNode(withName: "ship", recursively: false))!
// ship is 1 meter to right of origin
ship.position = SCNVector3(1, 0, 0)
// rotates the ship about the y-axis, so it's facing the same direction as the Earth's rotation
ship.eulerAngles = SCNVector3(0, 180.degreeToRadians(), 0)
// scale it down to 1/3 of size since it's large relative to other shapes
ship.scale = SCNVector3(0.3, 0.3, 0.3)
return ship
}
func drawSphereAtOriginWithImages() -> SCNNode {
let sphere = SCNNode(geometry: SCNSphere(radius: 0.05))
// sets the sphere to use earth image
sphere.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "earth")
// sets the sphere to use yellow shine
sphere.geometry?.firstMaterial?.specular.contents = UIColor.yellow
// sphere's origin is at (0,0,0)
sphere.position = SCNVector3(0, 0, 0)
/// rotate (360 degrees around its y-axis) the Sphere in 8 seconds once at the beginning of AR session
let rotateAction = SCNAction.rotate(by: 360.degreeToRadians(), around: SCNVector3(0, 1, 0), duration: 8)
/// repeat the rotation
let rotateForeverAction = SCNAction.repeatForever(rotateAction)
sphere.runAction(rotateForeverAction)
return sphere
}
func drawBoxAt1200High() -> SCNNode {
let box = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.0))
// sets the sphere to a flat white - diffuse = matte
box.geometry?.firstMaterial?.diffuse.contents = UIColor.orange
// sets the sphere to a shinyh white - specular = shine
box.geometry?.firstMaterial?.specular.contents = UIColor.white
// 20 centimeters above origin & 30 centimeters behind origin
box.position = SCNVector3(0, 0.2, -0.3)
return box
}
/// Challenge: Draw a pyramid
/// 10 centimeter high, 10 centimeter wide, 10 centimeter deep
/// green with red highlights
/// at 6'clock - 30 centimeters in front origin and 20 centimeters below origin
func drawPyramidAt600Low() -> SCNNode {
let pyramid = SCNNode(geometry: SCNPyramid(width: 0.10, height: 0.10, length: 0.10))
pyramid.geometry?.firstMaterial?.diffuse.contents = UIColor.green
pyramid.geometry?.firstMaterial?.specular.contents = UIColor.red
// 20 centimeters below origin & 30 centimeters in front origin
pyramid.position = SCNVector3(0, -0.20, 0.30)
return pyramid
}
/// Challenge: Draws plane with a cat image on its surface
/// 10 centimeter high, 10 centimeter wide
/// 20 centimeters to the left of origin
func drawCatOnAPlaneAt900() -> SCNNode {
let plane = SCNNode(geometry: SCNPlane(width: 0.10, height: 0.10))
plane.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "cat")
plane.geometry?.firstMaterial?.isDoubleSided = true
// sets the plane at centimeters to the left of origin
plane.position = SCNVector3(-0.20, 0, 0)
return plane
}
/// Draws a Torus (doughnut) at 3 o'clock
/// Ring Radius = 5 centimeters
/// Pipe Radius = 3 centimeters
/// 20 centimeters to the left of origin
/// 45 degree angle
func drawTorusAt300() -> SCNNode {
let torus = SCNNode(geometry: SCNTorus(ringRadius: 0.05, pipeRadius: 0.03))
torus.geometry?.firstMaterial?.diffuse.contents = UIColor.red
torus.geometry?.firstMaterial?.specular.contents = UIColor.white
torus.position = SCNVector3(0.20, 0, 0)
// sets the z axis to a 45 degree angle
torus.eulerAngles = SCNVector3(0, 0, 45.degreeToRadians())
return torus
}
/// Challenge: Draws plane with a cat image on its surface
/// 10 centimeter high, 10 centimeter wide
/// 20 centimeters to the left of origin
/// 45 degrees clockwise around x axis
/// 20 degrees counterclockwise around y axis
/// 45 degrees counterclockwise around z axis
func tiltTheCat() -> SCNNode {
let plane = SCNNode(geometry: SCNPlane(width: 0.10, height: 0.10))
plane.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "cat")
plane.geometry?.firstMaterial?.isDoubleSided = true
// sets the plane at centimeters to the left of origin
plane.position = SCNVector3(-0.20, 0, 0)
// 45 degrees clockwise around x axis, 20 degrees counterclockwise around y axis, 45 degrees counterclockwise around z axis
plane.eulerAngles = SCNVector3(-45.degreeToRadians(), 20.degreeToRadians(), 45.degreeToRadians())
return plane
}
// MARK: - ARSCNViewDelegate
/*
// Override to create and configure nodes for anchors added to the view's session.
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
let node = SCNNode()
return node
}
*/
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
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
}
}
extension Int {
/// Converts the Int in degrees to radians in CGFloat
/// - Returns: Radian in CGFloat
func degreeToRadians() -> CGFloat {
return CGFloat(self) * CGFloat.pi / 180.0
}
}
Til next time,
lovelejess
at 14:28