SceneKit 3D Programming for iOS: Getting Started

Learn how to use SceneKit for 3D graphics programming by building an app modeling the solar system. By Keegan Rush.

4.9 (13) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Adding the Ring

From the Object Library, find Tube and add it to the scene graph. Then, drag the tube so it nests under saturn, like so:

The tube as a child of Saturn in the scene graph

While all the planets are child nodes of the scene’s root node, you’ve added the tube as a child node of saturn. Now, you can position and animate the tube relative to its parent.

Think of this as adding car seats as children to a car node: if the car moves, the child nodes go along for the ride.

In the Node inspector, change the tube’s Position to x: 0, y: 0 and z: 0. This will center it on Saturn’s position.

Because it’s smaller than Saturn’s sphere, you won’t be able to see the tube. To size the tube appropriately, open the Attributes inspector. Then, make the following changes:

  • Inner radius: 7
  • Outer radius: 9
  • Height: 0.1

Sizing properties in Saturn's Attributes inspector

Now, your ring is positioned correctly, but it doesn’t match the rest of the planet. You could modify the material to match, or you could reuse the material you already styled for Saturn.

Reusing Material

When you’re making a large-scale scene, the ability to reuse objects is critical. In SceneKit, you can reuse nodes, geometries and materials. That way, if something has to change across the scene, you’ll only need to make the change once.

Right now, if you wanted to change Saturn’s color or anything else related to its material, you’d have to duplicate the changes in both the body of the planet and its ring. By sharing a material object, the planet and its ring will share the same appearance.

With the tube selected in the scene graph, open the Material inspector. At the top, you’ll find a collection of materials.

Materials collection for the tube

For Saturn’s ring, you only want one material that matches that of the planet’s body. So, click the minus (—) button to remove the tube’s material.

Empty materials collection

Then, click the plus (+) button to bring up the materials picker.

Materials picker

Find and click the saturn material, then click Done.

The Saturn material in the tube's Material inspector

Now, Saturn’s ring shares the same material as the planet’s body.

Build and run to see all the planets.

All planets in the running app

Your planets look great, but something’s missing. Your scene has light, but it looks a bit off — there’s no light coming from the sun. Next, you’ll fix that by adding a light to the sun node.

Attaching a Light

When you create a scene from a scene file, as you did with Solar Scene.scn, SceneKit gives you a running start by giving you a default camera, light and background. All you need to do is add your geometry.

In the scene graph, right-click the sun node.

Right-click context menu on the sun node

In this menu, you can choose between a collection of attachments: lights, cameras, physics bodies and more. For now, click Add Light.

Light attachment on the sun node

That little sun icon next to the sun node (how appropriate!) indicates the node has a light attachment. Similarly, the cube icon indicates a geometry attachment.

Click the sun node. Then, in the Inspectors panel, click the Attributes inspector.

Properties for the sun's light in the Attributes inspector

Earlier, you only had properties applicable to the attached geometry, but now you also have a new section for the attached light.

First, change the light’s Type to Omni, short for “omnidirectional”. This is a light type that shines in all directions. Then, change the Intensity to 20000. It is the sun, after all! :]

Build and run.

Sunlight in the running app

After that change, your whole solar system is basking in the sun’s warm glow.

You’ve gone as far as you need to in Solar Scene.scn. To really unlock the power of SceneKit, it’s time to start adding to your scene in your Swift code.

Adding Textures

So far, you’ve colored each planet with a single, simple color. Earth looks a little bland as a result, despite being known as the “blue planet.” To kick things up a notch, you’ll apply a texture to each planet instead of a color.

Textures are images that you wrap around geometries, such as your planet spheres. Remember those various color properties in the Material inspector? You can apply texture images to each of those properties as well.

In Xcode, open Assets.xcassets and look at the planets group.

Planet texture maps in the assets catalog

Each planet has an artificial map of its surface. When creating your scene, you’ll use these images to apply textures to each planet.

Replacing Colors with Textures

First, open ContentView.swift. Then, add this below makeScene():

static func applyTextures(to scene: SCNScene?) {
  // 1
  for planet in Planet.allCases {
    // 2
    let identifier = planet.rawValue
    // 3
    let node = scene?.rootNode
      .childNode(withName: identifier, recursively: false)

    // Images courtesy of Solar System Scope https://bit.ly/3fAWUzi
    // 4
    let texture = UIImage(named: identifier)

    // 5
    node?.geometry?.firstMaterial?.diffuse.contents = texture
  }
}

Here’s what’s happening, step by step:

  1. The Planet enumeration lists all planets in the app.
  2. Each planet’s rawValue is the same as the identifiers you’ve been applying to the planets: mercury, venus and so on.
  3. Using the identifier, grab a reference to the planet’s node.
  4. The names of the textures in Assets.xcassets also match the planet identifiers. This creates a UIImage for the appropriate planet.
  5. Finally, set the image as the planet’s diffuse on the node’s material, thereby replacing the color that served as its base appearance.

To apply your textures, add this to makeScene(), right before returning the scene:

applyTextures(to: scene)

This calls applyTextures(to:) while creating your scene.

Build and run. Then, take a closer look at each planet:

The earth texture in the running app

That looks much better. Textures are a great way to add realism to your scene. Next, to really get that “space” feeling, you’ll add one more texture.

Using Skybox Textures

Your planets are in great shape, but looking at the rest of your scene, it doesn’t look much like space. In Xcode, open Assets.xcassets and look in the skybox group.

Skybox images in the assets catalog

There’s not one, not two, but six images of a starry sky. Perfect for the scene’s background! But, why six? Well, SceneKit can use these six images for a common 3D programming technique known as a skybox. By using these images as the scene’s background, SceneKit makes a cube out of the six images and essentially puts the entire scene in the cube.

At the bottom of applyTextures(to:), add this:

// 1
let skyboxImages = (1...6).map { UIImage(named: "skybox\($0)") }
// 2
scene?.background.contents = skyboxImages

Here’s what’s going on:

  1. Create an array of the six skybox images.
  2. Use those images as the scene’s background contents.

SceneKit will handle the rest from here, as the framework knows to apply an array of six images as a skybox.

Finally, build and run to see what those two lines of code can do.

The skybox applied in the running app

No matter how you scroll or pan the image, you’re surrounded by a deep, starry sky. By using a skybox texture, you’ve shot your scene into outer space!

Your scene is finally taking shape. All that remains are some tweaks in how the app interfaces with SceneKit. For instance, the original app that shows planet info has no real link to the SceneKit scene. It’s time to change that.