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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
SceneKit 3D Programming for iOS: Getting Started
30 mins
- Getting Started
- Exploring Solar Scenes
- Creating Your First Scene
- Loading a Scene
- Adding Objects
- Modifying Materials
- Setting Up the Camera Node
- Creating Planets
- Adding Saturn’s Ring
- Adding the Ring
- Reusing Material
- Attaching a Light
- Adding Textures
- Replacing Colors with Textures
- Using Skybox Textures
- Working With the Camera
- Using Constraints
- Animating With Actions
- Focusing on the Selected Planet
- Where to Go From Here?
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:
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
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.
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.
Then, click the plus (+) button to bring up the materials picker.
Find and click the saturn material, then click Done.
Now, Saturn’s ring shares the same material as the planet’s body.
Build and run to see all the planets.
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.
In this menu, you can choose between a collection of attachments: lights, cameras, physics bodies and more. For now, click Add Light.
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.
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.
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.
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:
- The
Planet
enumeration lists all planets in the app. - Each planet’s
rawValue
is the same as the identifiers you’ve been applying to the planets:mercury
,venus
and so on. - Using the identifier, grab a reference to the planet’s node.
- The names of the textures in Assets.xcassets also match the planet identifiers. This creates a
UIImage
for the appropriate planet. - 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:
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.
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:
- Create an array of the six skybox images.
- 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.
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.