 # Introduction To SceneKit – Part 2

In this tutorial we’ll be looking at the various types of primitives you can use with SceneKit. We’ll look at how we can position objects in 3D space and ways of animating the positions of objects via actions.

Geometries in SceneKit are instances of the SCNGeometry class. Geometries provide the data necessary to draw the 3D objects they represent. Among other things this data is made up of verticesnormalstexture coordinates and indices. We also plan on releasing a series of tutorials on custom geometries which will explain all these concepts in detail.
If you want more information on geometry data in SceneKit have a look at this great tutorial this great tutorial which explains how to create custom geometries.

SceneKit provides the following basic primitives out of the box:

There’s also a set of more advanced and specialized objects which we’ll discuss in later tutorials:

Note that all of these classes subclass `SCNGeometry`.

Primitives are useful among other things for creating some basic shapes in your apps without importing 3D models designed in external programs. For example cylinder can represent barrels, boxes can represent crates, spheres can represent balls, etc.

Most primitives are positioned relative to their center unless noted otherwise. Let’s look at each primitive in part.

### Sphere

SCNSphere objects let you create 3D spheres. Spheres are defined using a `radius`, the distance from the center of the sphere to any point on the sphere.

Example:

`let sphere = SCNSphere(radius: 1.0)` ### Plane

SCNPlane objects let you create 2D planes by specifying the plane’s `width` and `height`. Planes result in a 2D geometry that is only visible from one side by default. To make planes visible from both sides set the `doubleSided`property

Example:

```let plane = SCNPlane(width: 1.0, height: 1.5)

// Make the plane visible from both sides
plane.firstMaterial?.doubleSided = true``` You can create a plane with rounded corners by setting the plane’s `cornerRadius` property. Example:

`plane.cornerRadius = 0.1` ### Box

SCNBox objects let you create cubes by specifying their `width``height` and `chamfer radius`

Boxes are defined width, height and length and chamfer radius:
`Width` is the length of the box along the x-axis.
`Height` is the length of the box along the y-axis.
`Length` is the length of the box along the z-axis.

Example:

`let box = SCNBox(width: 1.0, height: 1.5, length: 2.0, chamferRadius: 0.0)` The `chamferRadius` determines the amount by which the boxe’s corners should be rounded.

Example:

`box.chamferRadius = 0.05` ### Pyramid

SCNPyramid objects let you create pyramids by specifying the `width` and `length` of the base and the `height` of the pyramid.

Note that the pyramid is positioned relative to the center of it’s base instead of the center of the geometries like the other primitives.

Example:

`let pyramid = SCNPyramid(width: 2.0, height: 1.5, length: 1.0)` ### Cylinder

SCNCylinder objects let you create cylinders by specifying the cylinder’s `height` and the `radius` of it’s base. You can use cylinders to draw lines by specifying a small `radius`.

Example:

`let cylinder = SCNCylinder(radius: 1.0, height: 1.5)` ### Cone

SCNCone objects let you create cones and conical frustums(cones with their top cut off). You create cones by specifying a `bottom radius``top radius` and `height`.

Example:

`let cone = SCNCone(topRadius: 0.5, bottomRadius: 1.0, height: 1.5)` Example:

`let cone = SCNCone(topRadius: 0.0, bottomRadius: 1.0, height: 1.5)`

Notice that setting the `topRadius` property to 0.0 results in a cone. If `topRadius` is equal to `bottomRadius` the resulting geometry is a cylinder. ### Torus

Torus objects let you create donut like shapes by specifying a `ring radius` and a `pipe radius` (the actual radius of the donut). Have a look at the image below to see how these work.

Example:

`let torus = SCNTorus(ringRadius: 1.0, pipeRadius: 0.2)`

### Tube

Tube objects let you create cylinders with a hole going through their middle. You create cones by specifying the `outerRadius` (radius of the cylinder), `innerRadius`(radius of the hole going through it’s middle) and a `height`.

Example:

`let tube = SCNTube(innerRadius: 0.5, outerRadius: 1.0, height: 1.5)` ### Capsule

Capsule objects let you create cylinders that are capped with hemispheres at both ends. You create capsules by specifying their `height` and the `radius` of the hemispheres at the ends.

Example:

`let capsule = SCNCapsule(capRadius: 0.5, height: 2.0)` ### All primitives in a line

Let’s draw all the primitives mentioned above in a straight line along the x axis. First of all we’ll create an array to hold our geometries.

```var geometries = [SCNSphere(radius: 1.0),
SCNPlane(width: 1.0, height: 1.5),
SCNBox(width: 1.0, height: 1.5, length: 2.0, chamferRadius: 0.0),
SCNPyramid(width: 2.0, height: 1.5, length: 1.0),

We’ll then iterate through our array of geometries with an index. Create a new node with each geometry and add it to our root node in our scene.
We’ll keep track of the x position of our geometries incrementing it by 2.5 at each iteration of the loop.
We can get a cool coloring by creating colors with hue, saturation, brightness and varying the hue based on the index.

```var x:Float = 0.0
for index in 0..<geometries.count {

let hue:CGFloat = CGFloat(index) / CGFloat(geometries.count)
let color = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)

let geometry = geometries[index]
geometry.firstMaterial?.diffuse.contents = color

let node = SCNNode(geometry: geometry)
node.position = SCNVector3(x: x, y: 0.0, z: 0.0)

x += 2.5
}``` ### Hue Saturation Brightness

The UIColor initWithHue:saturation:brightness:alpha: constructor creates a new color instance by specifying it’s hue, saturation, brightness and alpha values. All these values have to be floating point numbers between 0 and 1.
To get a feeling for how these numbers affect the resulting color open up a color picker and play with the sliders. The above dark orange color can be created in code via:

`UIColor(hue: 25.0 / 359.0, saturation: 0.8, brightness: 0.7, alpha: 1.0)`

### All primitives in a circle

Let’s say we wanted to position our primitives in a circle. The gist of doing this is working in polar coordinates. Polar coordinates are the natural choice when dealing with coordinates that are along a circle and can be naturally expressed via a distance and an angle.

#### A short explanation of polar coordinates

Note: if you’re familiar with polar coordinates feel free to skip this section

Polar coordinates are used to represent 2D points via a radius and an angle.
The radius represents the distance from (0,0) to the point.
The angle represents the angle that the line connecting the point to (0,0) makes with the horizontal axis.

We can convert a point in polar coordinates to cartesian(x,y) coordinates by noticing that we can draw right triangle with vertices (0,0), our point and the projection of our point along the x-axis. (triangle OBC in the above figure). We know that the hypotenuse of the triangle is equal to the radius and that one of its angles is equal to our polar angle.
Using some basic trigonometry we can deduce the x and y coordinates by knowing the points radius and angle in polar coordinates.
By definition sin(angle) = Oposite / Hypotenusecos(angle) = Adjacent / Hypotenuse
In our case:

It follows that:

Note that when using the sin and cos functions in swift we have to specify the angle in radians. If you’re not familliar with radians have a look at this great explanation.

### Applying polar coordinates

We’ll be using polar coordinates to arrange our primitives in the XZ plane.
A radius of 4 is great for nicely arranging the primitives.
We’ll be starting the angle off at 0 and incrementing it by 2π / geometries.count so that the primitives are positioned uniform along the circle. We have to convert from polar coordinates to x,z coordinates when actually setting the position of the primitive.

```var angle:Float = 0.0
let angleIncrement:Float = Float(M_PI) * 2.0 / Float(geometries.count)

for index in 0..<geometries.count {

let hue:CGFloat = CGFloat(index) / CGFloat(geometries.count)
let color = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)

let geometry = geometries[index]
geometry.firstMaterial?.diffuse.contents = color

let node = SCNNode(geometry: geometry)

let x = radius * cos(angle)
let z = radius * sin(angle)

node.position = SCNVector3(x: x, y: 0, z: z)

angle += angleIncrement
}``` ### Animations

Let’s give our scene some life by animating the movement of our objects.

SceneKit provides a really convenient way of creating animations via the SCNAction class. It’s similar to the way animations in Cocos2D and SpriteKit work. You create an action and then you can run it on a node.

To animate the position of a node we have to create a new `SCNAction` via the class constructor `moveByX(_:y:z:duration:)` or `moveTo(_:duration:)`.

`moveByX(_:y:z:duration:)` moves a node by an x,y,z offset
`moveTo(_:duration:)` takes a SCNVector which represents the position where the node will end up at the end of the animation.
Both methods also take the duration of the animation as a parameter.

Example:

```let sphere = SCNSphere(radius: 1.0)
sphere.firstMaterial?.diffuse.contents = UIColor.redColor()
let sphereNode = SCNNode(geometry: sphere)

let moveUp = SCNAction.moveByX(0.0, y: 1.0, z: 0.0, duration: 1.0)
sphereNode.runAction(moveUp)``` Actions can be composed by creating a sequence. For example if we wanted to move the sphere up and then down again we would create two animations and composite them into a sequence animation then run the sequence animation on the sphere node.
Sequence animations are created via the constructor `sequence(actions)` were actions is an array of actions that will be played in a sequence.

Example:

```let moveUp = SCNAction.moveByX(0.0, y: 1.0, z: 0.0, duration: 1.0)
let moveDown = SCNAction.moveByX(0.0, y: -1.0, z: 0.0, duration: 1.0)
let sequence = SCNAction.sequence([moveUp,moveDown])
sphereNode.runAction(sequence)``` Actions can be repeated by creating a new action via one of the constructors:
`repeatAction(_:count:)` – Repeats the action count times
`repeatActionForever(_:)` – Repeats the action forever

Example:

```let moveUp = SCNAction.moveByX(0.0, y: 1.0, z: 0.0, duration: 1.0)
let moveDown = SCNAction.moveByX(0.0, y: -1.0, z: 0.0, duration: 1.0)
let sequence = SCNAction.sequence([moveUp,moveDown])
let repeatedSequence = SCNAction.repeatActionForever(sequence)
sphereNode.runAction(repeatedSequence)```

Let’s also have a look at how we can animate our circle of primitives. We can create a `SCNAction` instance and run it inside the loop where we create our node.

```  let sign:CGFloat = index % 2 == 0 ? 1.0 : -1.0
let move1 = SCNAction.moveByX(0.0, y: sign * CGFloat(1.0), z: 0.0, duration: 1.0)
let move2 = SCNAction.moveByX(0.0, y: sign * CGFloat(-1.0), z: 0.0, duration: 1.0)
let sequence = SCNAction.sequence([move1,move2])
let repeatedSequence = SCNAction.repeatActionForever(sequence)```

The animation we’re creating here is similar to the one above. Only we alternate the movement between up/down and down/up based on the index. Check out the documentation for a complete list of actions available in SceneKit.

Next time we’ll look at at making a 3D simulation of the Towers of Hanoi problem.

### Challenges

1) Add a new node to the scene with a geometry of type SCNFloor, position it below the primitives. The floor is an infinite plane that reflects the geometries above it. Try tweaking the intensity of the reflection via the floor’s `reflectivity` property.

Solution

```let floor = SCNFloor()
let floorNode = SCNNode(geometry: floor)
floorNode.position.y = -2.5

[collapse] 2) Position the primitives in a spiral that goes twice around the origin

Hint1

Increase the y coordinate at each iteration

[collapse]
Hint2

You have to make the angle increment 2 times bigger to go twice around the circle

[collapse]
Solution

```var angle:Float = 0.0
let angleIncrement:Float = Float(M_PI) * 4.0 / Float(geometries.count)

var y:Float = 0.0

for index in 0..<geometries.count {

let hue:CGFloat = CGFloat(index) / CGFloat(geometries.count)
let color = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)

let geometry = geometries[index]
geometry.firstMaterial?.diffuse.contents = color

let node = SCNNode(geometry: geometry)

let x = radius * cos(angle)
let z = radius * sin(angle)

node.position = SCNVector3(x: x, y: y, z: z)

angle += angleIncrement
y += 2.0
}
```

[collapse] 3) Draw a flight of stairs 20 stairs.

Solution

```let numberOfStairs = 20
let stairWidth:CGFloat = 1.0
let stairHeight:CGFloat = 0.2
let stairLength:CGFloat = 0.5

var z:Float = 0.0
var y:Float = 0.0

for index in 0..<numberOfStairs {

let hue:CGFloat = CGFloat(index) / CGFloat(numberOfStairs)

let stairNode = SCNNode(geometry: SCNBox(width: stairWidth, height: stairHeight, length: stairLength, chamferRadius: 0.0))

if (index % 3 == 0) {
stairNode.geometry?.firstMaterial?.diffuse.contents = UIColor.redColor()
} else if (index % 3 == 1){
stairNode.geometry?.firstMaterial?.diffuse.contents = UIColor.orangeColor()
} else {
stairNode.geometry?.firstMaterial?.diffuse.contents = UIColor.purpleColor()
}

stairNode.position = SCNVector3(x: 0.0, y: y, z: z)

y += Float(stairHeight)
z += Float(stairLength)

}```

[collapse] 4) Draw a fir tree by stacking N cones on top of each other. Make the base a cylinder. Make the topmost cone have a topRadius of 0.

Solution

```let baseHeight:CGFloat = 0.8
let treeBase = SCNNode(geometry: SCNCylinder(radius: 0.2, height: baseHeight))

treeBase.geometry?.firstMaterial?.diffuse.contents = UIColor.brownColor()

let numberOfLevels = 4

var y:Float = Float(baseHeight / 2.0)
var leaveHeight:CGFloat = 0.4
let lastLevelHeight:CGFloat = 0.6

let scale:CGFloat = 0.8
for i in 0..<numberOfLevels {

if (i == numberOfLevels - 1) {

y += Float((lastLevelHeight - leaveHeight) / 2.0)
leaveHeight = lastLevelHeight

}

leavesNode.position.y = y
y += Float(leaveHeight)

leavesNode.geometry?.firstMaterial?.diffuse.contents = UIColor.greenColor()

}```

[collapse] 5) Draw a toy by stacking N tori on top of each other with a cone in the middle Note: Tori are transparent for reference.

Solution

```let numberOfTori = 6

var cylinderHeight:CGFloat = 2.5

let cylinderNode = SCNNode(geometry: cylinder)

cylinderNode.position.y += Float(cylinderHeight) / 2.0 - Float(pipeRadius)

var y:Float = 0.0
for index in 0..<numberOfTori {

let hue:CGFloat = CGFloat(index) / CGFloat(numberOfTori)
let color = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)

torus.firstMaterial?.diffuse.contents = color
torus.firstMaterial?.transparency = 0.8

let torusNode = SCNNode(geometry: torus)

torusNode.position = SCNVector3(x: 0.0, y: y, z: 0.0)

}

[collapse] 6) Create a 25×25 grid of capsules in the unit square on the XZ plane. Animate they’re movement along the Y Axis. Determine the amount of movement via a 2 variable function. Color each capsule with a hue of abs(x * z)

Hint

The unit square is the square in the XZ planewith corners of coordinates (-1,0,1), (1,0,1), (1,0,-1), (-1,0,-1).

[collapse]

Solution

```func sinFunction(x: Float,z: Float) -> Float {
return 0.2 * sin(x * 5 + z * 3) + 0.1 * cos(x * 5 + z * 10 + 0.6) + 0.05 * cos(x * x * z)
}

func squareFunction(x: Float,z: Float) -> Float {
return x * x + z * z
}

let gridSize = 25

let capsuleRadius:CGFloat = 1.0 / CGFloat(gridSize - 1)
let capsuleHeight:CGFloat = capsuleRadius * 4.0

var z:Float = Float(-gridSize + 1) * Float(capsuleRadius)

for row in 0..<gridSize {
var x:Float = Float(-gridSize + 1) * Float(capsuleRadius)
for column in 0..<gridSize {

let hue = CGFloat(abs(x * z))
let color = UIColor(hue: hue, saturation: 1.0, brightness: 1.0, alpha: 1.0)

capsule.firstMaterial?.diffuse.contents = color

let capsuleNode = SCNNode(geometry: capsule)

capsuleNode.position = SCNVector3Make(x, 0.0, z)

let y = CGFloat(squareFunction(x,z: z))
//let y = CGFloat(sinFunction(x, z: z))

let moveUp = SCNAction.moveByX(0, y: y, z: 0, duration: 1.0)
let moveDown = SCNAction.moveByX(0, y: -y, z: 0, duration: 1.0)

let sequence = SCNAction.sequence([moveUp,moveDown])

let repeatedSequence = SCNAction.repeatActionForever(sequence)

capsuleNode.runAction(repeatedSequence)

}

}
```

[collapse]

For example here’s `x² + z²` And here’s: `0.2 * sin(5 * x + 3 * z) + 0.1 * cos(5 * x + 10 * z + 0.6) + 0.05 * cos(x * x * z)` BONUS: Find some interesting 2D functions for these sort of animations     (5 votes, average: 3.00 out of 5) Loading...

## 7 comments for “Introduction To SceneKit – Part 2”

1. Atharva Vaidya
November 18, 2014 at 2:50 pm

Loved the tutorial! Please do some more for SceneKit. Could you tell me how I could make a 3D Rectangular grid?

2. Atharva Vaidya
November 18, 2014 at 2:54 pm

Something like this:

http://imgur.com/rS4ElIA

• Grustaf
November 22, 2014 at 8:50 pm

You need to use open gl primitives then, specifically lines, using custom geometry. You can do that sort of easily in Scenekit, but animating the mesh is slow because you need to rebuild the geometry on every frame. If you post a question on stack overflow you’ll get a longer answer…

• November 26, 2014 at 4:33 pm

Have a look at that shows you how to draw a wireframe cube.

3. A guy
November 18, 2014 at 3:06 pm

Thank you so much for the great tutorial. This is very helpful.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe
We send about one email per week with our latest tutorials and updates
Never display this again :)