Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
View an ARKit Solar System In Your Room
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
// light source
sceneView.autoenablesDefaultLighting = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// show world origin
// sceneView.debugOptions = [ARSCNDebugOptions.showWorldOrigin, ARSCNDebugOptions.showFeaturePoints]
// Run the view's session
sceneView.session.run(configuration)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// sun
let sun = SCNNode(geometry: SCNSphere(radius: 0.35))
sun.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "starSunDiffuse")
sun.position = SCNVector3Make(0.0, 0.0, -1.5)
sceneView.scene.rootNode.addChildNode(sun)
// rotate (spin) the sun around itself
let rotationAction = SCNAction.rotateBy(x: 0.0, y: CGFloat(360.degreesToRadians), z: 0.0, duration: 60.0)
let rotationPeriod = SCNAction.repeatForever(rotationAction)
sun.runAction(rotationPeriod)
// create parent nodes of planets so they can have their own motions
let earthParentNode = SCNNode()
let moonParentNode = SCNNode()
earthParentNode.position = SCNVector3Make(0.0, 0.0, -1.5)
moonParentNode.position = SCNVector3Make(0.0, 0.0, 0.0)
sceneView.scene.rootNode.addChildNode(earthParentNode)
// earth appearance & position
let earth = astralBody(geometry: SCNSphere(radius: 0.2), diffuse: UIImage(named: "planetEarth")!, specular: UIImage(named: "planetEarthSpecular")!, emission: UIImage(named: "planetEarthEmissive")!, normal: UIImage(named: "planetEarthNormal")!, position: SCNVector3Make(1.2, 0.0, 0.0))
// moon appearance & position
let moon = astralBody(geometry: SCNSphere(radius: 0.07), diffuse: UIImage(named: "moonLunaDiffuse")!, specular: nil, emission: nil, normal: nil, position: SCNVector3Make(0.5, 0.0, 0.0))
// add actual bodies to parent nodes
earthParentNode.addChildNode(earth)
moonParentNode.addChildNode(moon)
earth.addChildNode(moonParentNode)
// set body rotations (spin), and orbits
let earthRotationPeriod = nodeRotation(time: 12.0, x: 0.0, y: -CGFloat(360.degreesToRadians), z: 0.0)
earth.runAction(earthRotationPeriod)
let earthParentRotationPeriod = nodeRotation(time: 30.0, x: 0.0, y: CGFloat(360.degreesToRadians), z: 0.0)
earthParentNode.runAction(earthParentRotationPeriod)
// spin
let moonRotationPeriod = nodeRotation(time: 6.0, x: 0.0, y: CGFloat(360.degreesToRadians), z: 0.0)
moon.runAction(moonRotationPeriod)
// orbit
let moonParentRotationPeriod = nodeRotation(time: 3.0, x: 0.0, y: CGFloat(360.degreesToRadians), z: 0.0)
moonParentNode.runAction(moonParentRotationPeriod)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func nodeRotation(time: TimeInterval, x: CGFloat, y: CGFloat, z: CGFloat) -> SCNAction {
let rotationAction = SCNAction.rotateBy(x: x, y: y, z: z, duration: time)
let rotationPeriod = SCNAction.repeatForever(rotationAction)
return rotationPeriod
}
func astralBody(geometry: SCNGeometry, diffuse: UIImage?, specular: UIImage?, emission: UIImage?, normal: UIImage?, position: SCNVector3) -> SCNNode {
let body = SCNNode(geometry: geometry)
body.geometry?.firstMaterial?.diffuse.contents = diffuse
body.geometry?.firstMaterial?.specular.contents = specular
body.geometry?.firstMaterial?.emission.contents = emission
body.geometry?.firstMaterial?.normal.contents = normal
body.position = position
return body
}
// MARK: - ARSCNViewDelegate
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 {
var degreesToRadians: Double { return Double(self) * .pi/180 }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.