Adding spheres to a scene using ARKit

Just some spheres floating above my bed


First we’ll want to set up the basic ARKit scene. All this is boilerplate provided if you create an ARKit project in XCode

//  ViewController.swift

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {

        // Set the view's delegate
        sceneView.delegate = self

        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true

        // Create a new scene
        let scene = SCNScene()

        // Set the scene to the view
        sceneView.scene = scene

    override func viewWillAppear(_ animated: Bool) {

        // Create a session configuration
        let configuration = ARWorldTrackingSessionConfiguration()
        configuration.planeDetection = .horizontal

        // Run the view's session

    override func viewWillDisappear(_ animated: Bool) {

        // Pause the view's session

One nice thing to add when developing with ARKit is the debug point thingies:

// Goes in viewDidLoad()
sceneView.debugOptions = ARSCNDebugOptions.showFeaturePoints


Now, we’ll create a separate sphere class to abstract away the SCNNodes which will contain the sphere:

//  Sphere.swift

import Foundation
import ARKit

class Sphere: SCNNode {

    static let radius: CGFloat = 0.01

    let sphereGeometry: SCNSphere

    // Required but unused
    required init?(coder aDecoder: NSCoder) {
        sphereGeometry = SCNSphere(radius: Sphere.radius)
        super.init(coder: aDecoder)

   	// The real action happens here
    init(position: SCNVector3) {
        self.sphereGeometry = SCNSphere(radius: Sphere.radius)


        let sphereNode = SCNNode(geometry: self.sphereGeometry)
        sphereNode.position = position


    func clear() {


Now, when we want to add a sphere, we can do something like this

    func addSphere(position: SCNVector3) {
        print("adding sphere at point: \(position)")
        let sphere: Sphere = Sphere(position: position)
// if we keep an array of these babies, then calling
// sphere.clear() on each will remove them from the scene

Insert into scene

Now for the interseting bit. To calculate the position at which we’d like to place the sphere, we can take the position of the camera and add a transform in the direction the camera is facing. All this code could be executed in a button press handler, for instance.

I found this handy screenSpacePosition function in a stack overflow post, it’ll do the vector math addition along the z axis. The distance is negative because we want to go further into the scene.

    func sceneSpacePosition(inFrontOf node: SCNNode, atDistance distance: Float) -> SCNVector3 {
        let localPosition = SCNVector3(x: 0, y: 0, z: -distance)
        let scenePosition = node.convertPosition(localPosition, to: nil)
        // to: nil is automatically scene space
        return scenePosition

then, in the button press handler:

if let cameraNode = self.sceneView.pointOfView {

	let distance: Float = 0.3 // Hardcoded depth
    let pos = sceneSpacePosition(inFrontOf: cameraNode, atDistance: distance)    

    addSphere(position: pos)


Another way to do this would be to try to add the object “into” the scene, at a depth which is the location in z space of the object in front of the camera. We can do this with a hit test:

if let cameraNode = self.sceneView.pointOfView {

	let width = sceneView.frame.size.width;
	let height = sceneView.frame.size.height;

	let distance = sceneView.hitTest(CGPoint(x: width, y: height), types: [.existingPlaneUsingExtent, .featurePoint]).first!.distance;
	let pos = sceneSpacePosition(inFrontOf: cameraNode, atDistance: Float(distance))

    addSphere(position: pos)

And that’s all for this post!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: