Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@jungchris
Last active August 7, 2020 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jungchris/0eb5a1a8cc13772762baaadc9ec0c669 to your computer and use it in GitHub Desktop.
Save jungchris/0eb5a1a8cc13772762baaadc9ec0c669 to your computer and use it in GitHub Desktop.
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