29

I've looked everywhere for this but I'm coming up blank. How do you replicate what Chris Lattner was demonstrating with Playgrounds and SceneKit at WWDC? I want to have a SceneKit scene, animating, in Playgrounds.

I tried cutting and pasting the setup code from the SceneKit project template, thinking it would magically start rendering, but it does not.

I tried watching the keynote and pausing and zooming on on Lattner's screen looking for hints at the source code, but he appeared to be importing all his code from elsewhere in his project, so it gave me no clues. There does not seem to be anything in the documentation, or I'm missing it.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
user1845848
  • 653
  • 2
  • 8
  • 11

5 Answers5

53

Since Swift doesn't have source compatibility between versions, the code in this answer might not work in either future or previous versions of Swift. Currently is has been updated to work in Xcode 7.0 Playgrounds with Swift 2.0.


The XCPlayground framework is what you need, and it is documented here.

Here is a very simple scene to get you started with Scene Kit in Swift:

import SceneKit
import QuartzCore   // for the basic animation
import XCPlayground // for the live preview
import PlaygroundSupport

// create a scene view with an empty scene
var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var scene = SCNScene()
sceneView.scene = scene

// start a live preview of that view
PlaygroundPage.current.liveView = sceneView

// default lighting
sceneView.autoenablesDefaultLighting = true

// a camera
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 3)
scene.rootNode.addChildNode(cameraNode)

// a geometry object
var torus = SCNTorus(ringRadius: 1, pipeRadius: 0.35)
var torusNode = SCNNode(geometry: torus)
scene.rootNode.addChildNode(torusNode)

// configure the geometry object
torus.firstMaterial?.diffuse.contents  = NSColor.red   // (or UIColor on iOS)
torus.firstMaterial?.specular.contents = NSColor.white // (or UIColor on iOS)

// set a rotation axis (no angle) to be able to
// use a nicer keypath below and avoid needing
// to wrap it in an NSValue
torusNode.rotation = SCNVector4(x: 1.0, y: 1.0, z: 0.0, w: 0.0)

// animate the rotation of the torus
var spin = CABasicAnimation(keyPath: "rotation.w") // only animate the angle
spin.toValue = 2.0*Double.pi
spin.duration = 3
spin.repeatCount = HUGE // for infinity
torusNode.addAnimation(spin, forKey: "spin around")

When I run it, it looks like this:

enter image description here


Note that to run Scene Kit in an iOS playground, you need to check the "Run in Full Simulator" checkbox.

enter image description here

You find the Playground Setting in the Utilities Pane (0 to hide or show)

Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • 1
    This is not working if the playground is targetted for iOS. I am using xcode 6 beta 6. You get a total blank instead of the torus. – kawingkelvin Aug 29 '14 at 00:04
  • using Xcode 6.1, with playground targeting iOS 8, only get "SCNView", "SCNScene", ...etc text output, there's no image displayed. – New2ObjectiveC Dec 28 '14 at 12:48
  • @New2ObjectiveC You need to configure the playground to "Run in Full Simulator" to render Scene Kit in iOS playgrounds (see updated answer). The original answer was a OS X playground (and still is but includes commented out iOS code) – David Rönnqvist Dec 30 '14 at 10:36
  • 2
    Thanks David, got it working. Also found that the main trick is to click on the "show the assistance editor" icon (the icon of the suit + bow tie). – New2ObjectiveC Jan 09 '15 at 04:47
  • Shared some info on my blog: http://new2objectivec.blogspot.com.au/2015/01/using-scenekit-in-swift-playground-for.html – New2ObjectiveC Jan 09 '15 at 05:57
  • doesn't work with iOS 8.2 `2015-05-20 14:41:37.458 drawline[76343:732082] Error sending deferral props: 0x10000003` – μολὼν.λαβέ May 20 '15 at 21:42
  • Im using Xcode 7.0.1 and I get an error when I compile that code, after I fix the first error it gives `error: Playground execution aborted: Execution was interrupted, reason: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0). ` on the line `var camera = SCNCamera() ` – Pocketkid2 Oct 02 '15 at 17:44
  • link has gone bad, update: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/XCPlaygroundModuleRef/XCPlayground.html – bshirley Apr 28 '16 at 20:11
9

To get the playground running with iOS as target, and using the latest Xcode 8.1, I got it working with the following modifications to David Rönnqvist's original code.

import UIKit
import SceneKit
import QuartzCore   // for the basic animation
import PlaygroundSupport


// create a scene view with an empty scene
var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
var scene = SCNScene()
sceneView.scene = scene
PlaygroundPage.current.liveView = sceneView

// default lighting
sceneView.autoenablesDefaultLighting = true

// a camera
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 3)
scene.rootNode.addChildNode(cameraNode)

// a geometry object
var torus = SCNTorus(ringRadius: 1, pipeRadius: 0.35)
var torusNode = SCNNode(geometry: torus)
scene.rootNode.addChildNode(torusNode)

// configure the geometry object
torus.firstMaterial?.diffuse.contents  = UIColor.red
torus.firstMaterial?.specular.contents = UIColor.white

// set a rotation axis (no angle) to be able to
// use a nicer keypath below and avoid needing
// to wrap it in an NSValue
torusNode.rotation = SCNVector4(x: 1.0, y: 1.0, z: 0.0, w: 0.0)

// animate the rotation of the torus
var spin = CABasicAnimation(keyPath: "rotation.w") // only animate the angle
spin.toValue = 2.0*M_PI
spin.duration = 3
spin.repeatCount = HUGE // for infinity
torusNode.addAnimation(spin, forKey: "spin around")

The main things you have to do different are:

  • to assign to the playground's liveView and,
  • also open up Xcode's Assistant Editor (The two intersecting circles icon on the toolbar)
Dhiraj Gupta
  • 9,704
  • 8
  • 49
  • 54
  • Thanks for that answer! According to the age of this post it should be the actual solution. Working for the playgrounds app as well. – J. Kreller May 08 '20 at 21:11
5

Expanding on Moshe's response.

If that keyboard combination doesn't work for you, try going to the the menu bar and select View > Assistant Editor > Show Assistant.

NerdBird
  • 51
  • 1
  • 3
3

In Xcode 10.2 and higher, there's a PlaygroundSupport framework. It shares a playground data, manages live views, and controls the execution of a playground.

import PlaygroundSupport

You can use Playground Support from within playgrounds to:

  • Access a playground page and manage its execution
  • Access and share persistent data
  • Assess the progress of the learner, update hints, and show success text

About Swift Playgrounds for iPad read here.


Here's the code:

import PlaygroundSupport
import SceneKit

var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 1000, height: 200))
var scene = SCNScene()
sceneView.scene = scene
sceneView.backgroundColor = .black
PlaygroundPage.current.liveView = sceneView

var lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .directional
lightNode.light?.intensity = 3000
lightNode.light?.shadowMode = .deferred
lightNode.rotation = SCNVector4(x: 0, y: 0, z: 0.5, w: 1.5 * Float.pi)
scene.rootNode.addChildNode(lightNode)

var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 2.5, y: 0, z: 5)
scene.rootNode.addChildNode(cameraNode)

var box = SCNBox(width: 3, height: 3, length: 3, chamferRadius: 0.4)
var boxNode = SCNNode(geometry: box)
scene.rootNode.addChildNode(boxNode)

box.firstMaterial?.diffuse.contents  = UIColor.blue
box.firstMaterial?.specular.contents = UIColor.purple
boxNode.rotation = SCNVector4(x: 1.0, y: 1.0, z: 0.0, w: 0.0)
boxNode.scale = SCNVector3(x: 1.0, y: 1.0, z: 1.0)

Then apply a transform animation:

var spin = CABasicAnimation(keyPath: "rotation.w")
var scale = CABasicAnimation(keyPath: "scale.x")
spin.toValue = 3 * -CGFloat.pi
spin.duration = 2
spin.repeatCount = .greatestFiniteMagnitude
scale.toValue = 1.5
scale.duration = 2
scale.repeatCount = .infinity
boxNode.addAnimation(spin, forKey: "spin around")
boxNode.addAnimation(scale, forKey: "scale x")

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
1

If the playground is complaining with 'int is not convertible to CGFloat' then you can use this line of code:

spin.toValue = NSValue(SCNVector4: SCNVector4(x: 1, y: 1, z: 0, w: CGFloat(2.0*M_PI)))

Implicit typecasts seem not to be defined in swift.

Eimantas
  • 48,927
  • 17
  • 132
  • 168
JackPearse
  • 2,922
  • 23
  • 31