• Stars
    star
    150
  • Rank 247,323 (Top 5 %)
  • Language
    Swift
  • Created over 9 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

CoreMotion Controlled Drawing in 3D Space

SwiftSpace

Gyroscope Driven Drawing in 3D Space

Companion project to: http://flexmonkey.blogspot.co.uk/2015/08/coremotion-controlled-3d-sketching-on.html

I was really impressed by a demo of InkScape that I read about in Creative Applications recently. InkScape is an Android app which allows users to sketch in a 3D space that's controlled by the device's accelerometer. It's inspired by Rhonda which pre-dates accelerometers and uses a trackball instead.

Of course, my first thought was, "how can I do this in Swift?". I've never done any work with CoreMotion before, so this was a good opportunity to learn some new stuff. My first port of call was this excellent article on iOS motion at NSHipster.

My plan for the application was to have a SceneKit scene with a motion controlled camera rotating around an offset pivot point at the centre of the SceneKit world. With each touchesBegan(), I'd create a new flat box in the centre of the screen that aligned with the camera and on touchesMoved(), I'd use the touch location to append to a path that I'd draw onto a CAShapeLayer that I'd use as the diffuse material for the newly created geometry.

Easy! Let's break it down:

Creating the Camera

I wanted the camera at to always point at and rotate around the centre of the world while being slightly offset from it. The two things to help this are the camera's pivot property and using a "look at constraint". First off, I create a node to represent the centre of the world and the camera itself:

    let centreNode = SCNNode()
    centreNode.position = SCNVector3(x: 0, y: 0, z: 0)
    scene.rootNode.addChildNode(centreNode)

    let camera = SCNCamera()
    camera.xFov = 20

    camera.yFov = 20

Next, an SCNLookAtConstraint means that however I translate the camera, it will always point at the centre:

    let constraint = SCNLookAtConstraint(target: centreNode)
    cameraNode.constraints = [constraint]

...and finally, setting the camera's pivot will reposition it but have it rotate around the centre of the world:

    cameraNode.pivot = SCNMatrix4MakeTranslation(0, 0, -cameraDistance)

Handling iPhone Motion

Next up is handling the iPhone's motion to rotate the camera. Remembering that the iPhone's roll is its rotation along the front-to-back axis and its pitch is its rotation along its side-to-side axis:

...I'll use those properties to control my camera's x and y Euler angles.

The first step is to create an instance of CMMotionManager and ensure it's available and working (so this code won't work on the simulator):

    let motionManager = CMMotionManager()
        
    guard motionManager.gyroAvailable else
    {
        fatalError("CMMotionManager not available.")

    }

Next up, I start the motion manager with a little block of code that's invoked with each update. I use a tuple to store the initial attitude of the iPhone and simple use the difference between that initial value and the current attitude to set the camera's Euler angles:

    let queue = NSOperationQueue.mainQueue
    
    motionManager.deviceMotionUpdateInterval = 1 / 30
    
    motionManager.startDeviceMotionUpdatesToQueue(queue())
    {
        (deviceMotionData: CMDeviceMotion?, error: NSError?) in
        
        if let deviceMotionData = deviceMotionData
        {
            if (self.initialAttitude == nil)
            {
                self.initialAttitude = (deviceMotionData.attitude.roll,
                    deviceMotionData.attitude.pitch)
            }
            
            self.cameraNode.eulerAngles.y = Float(self.initialAttitude!.roll - deviceMotionData.attitude.roll)
            self.cameraNode.eulerAngles.x = Float(self.initialAttitude!.pitch - deviceMotionData.attitude.pitch)
        }

    }

##Drawing in 3D

Since I know the angles of my camera, it's pretty simple to align the target geometry for drawing on the touchesBegan() method - it just shares the same attitude:

    currentDrawingNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 0, chamferRadius: 0))

    currentDrawingNode.eulerAngles.x = self.cameraNode.eulerAngles.x
    currentDrawingNode.eulerAngles.y = self.cameraNode.eulerAngles.y

At the same time, I create a new CAShapeLayer that will contain a stroked path that follows the user's finger:

    currentDrawingLayer = CAShapeLayer()

    let material = SCNMaterial()

    material.diffuse.contents = currentDrawingLayer
    material.lightingModelName = SCNLightingModelConstant
            

    currentDrawingNode.geometry?.materials = [material]

On touchesMoved(), I need to convert the location in the main view to the location on the geometry. Since this geometry has a size of 1 x 1 (from -0.5 through 0.5 in both directions), I'll need to convert that to coordinates in my CAShapeLayer (arbitrarily set to 512 x 512) to add points its path.

There are a few steps to do this, taking the locationInView() of the first item in the touches set, I pass it into hitTest() on my SceneKit scene. This returns an array of SCNHitTestResults for all the geometries underneath the touch which I filter for the current geometry and then simply rescale the result's localCoordinates to find the coordinates on the current CAShapeLayer:

    let locationInView = touches.first?.locationInView(view)

    if let hitTestResult:SCNHitTestResult = sceneKitView.hitTest(locationInView!, options: nil).filter( { $0.node == currentDrawingNode }).first,
        currentDrawingLayer = currentDrawingLayer

    {
        let drawPath = UIBezierPath(CGPath: currentDrawingLayer.path!)

        let newX = CGFloat((hitTestResult.localCoordinates.x + 0.5) * Float(currentDrawingLayerSize))
        let newY = CGFloat((hitTestResult.localCoordinates.y + 0.5) * Float(currentDrawingLayerSize))
        
        drawPath.addLineToPoint(CGPoint(x: newX, y: newY))
        
        currentDrawingLayer.path = drawPath.CGPath
    }

...and that's kind of it!

The source code to this project is available here at my GitHub repository. It was developed under Xcode 7 beta 5 and tested on my iPhone 6 running iOS 8.4.1.

More Repositories

1

Filterpedia

Core Image Filter Explorer & Showcase
Swift
2,241
star
2

Blurable

Apply a Gaussian Blur to any UIView with Swift Protocol Extensions
Swift
932
star
3

Plum-O-Meter

3D Touch Application for Weighing Plums (and other small fruit!)
Swift
528
star
4

ParticleLab

Particle system that's both calculated and rendered on the GPU using the Metal framework
Swift
493
star
5

sweetcorn

Node based CIKernel creation
Swift
261
star
6

SmoothScribble

Smooth Drawing for iOS in Swift with Hermite Spline Interpolation
Swift
241
star
7

MarkingMenu

Swift MarkingMenu
Swift
217
star
8

CartoonEyes

Composite Cartoon Eyes over Face from Front Camera with CoreImage
Swift
163
star
9

LiveCameraFiltering

Demonstration of applying a Comic Book filter to a live video feed
Swift
151
star
10

ShinpuruLayout

Simple Layout in Swift using HGroups & VGroups
Swift
128
star
11

ForceSketch

Demonstration of a Sketching App Using 3D Touch
Swift
109
star
12

ParticleCam

Metal based particle system influenced by iPad camera
Swift
102
star
13

ShinpuruImage

Syntactic Sugar for Accelerate/vImage and Core Image Filters
Swift
100
star
14

ShinpuruNodeUI

Node Based UI Component Written in Swift
Swift
98
star
15

ValentinesSwift

You love Swift & Swift loves you!
Swift
89
star
16

CoreImageForSwiftPlaygrounds

CoreImage For Swift Playgrounds
Swift
88
star
17

SnapSwift

SnapSeed Style Popup Menu for iOS
Swift
87
star
18

CoreImageHelpers

Syntactic sugar for displaying CIImage using OpenGL and grabbing CIImages from iOS cameras
Swift
73
star
19

VideoEffects

iPad app to open videos from file system, apply Core Image filters and save result back SavedPhotosAlbum
Swift
71
star
20

AudioKitNodality

AudioKitNodality
Swift
69
star
21

MetalReactionDiffusion

Reaction Diffusion using Swift & Metal
Swift
69
star
22

3D-Motion-Controller

Using MultipeerConnectivity and CoreMotion to allow an iPhone to act as a 3D mouse for an iPad app
Swift
67
star
23

Globular

Colourful SpriteKit Metaballs Controlled by 3D Touch
Swift
67
star
24

Interpolation-Playground-

Swift playground demonstrating lerp, smooth step, Catcall-Rom and others!
Swift
63
star
25

Nebula

Core Image Volumetric Rendering
Swift
60
star
26

MetalKit-Particles

An implementation of my Metal ParticleLab component for OS X 10.11 and iOS 9
Swift
57
star
27

AdvancedTouch

Swift Advanced Touch Handling in iOS9: Coalescing and Prediction
Swift
50
star
28

MetalVideoCapture

Demo of Creating a Metal Texture from AVCaptureSession and Applying MetalPerformanceShaders In-Place
Swift
50
star
29

AudioSynthesis

CoreAudio for Sound Synthesis Demonstration
Swift
48
star
30

UIScrollViewDemo

A Node Based User Interface implemented with the Presentation Model Pattern
Swift
41
star
31

SwiftCFD

CPU Based Navier Stokes Computational Fluid Dynamics in Swift for iOS
Swift
41
star
32

StrangeAttractor

Lorenz Attractor in Swift & Metal
Swift
39
star
33

Spritely

Using SpriteKit events to trigger AudioKit sounds
Swift
39
star
34

SwiftGoo

Kai's Power Tools Goo - written in Swift!
Swift
38
star
35

Scribe

Handwriting and Stroke Recognition in Swift
Swift
37
star
36

DeepPressGestureRecognizer

UIGestureRecognizer for recognising deep press 3D Touch on iPhone 6s
Swift
35
star
37

MercurialPaint

Mercurial Painting using Metal and Core Image
Swift
33
star
38

PencilController

Using Apple Pencil as a 3D Controller for Image Editing
Swift
30
star
39

CoreImagePerspectivePlayground

Core Image Perspective Playground
Swift
28
star
40

GameplayKitAgents

A Look at Agents, Goals & Behaviours in GameplayKit
Swift
27
star
41

CoreImageFluidDynamics

CIFilter / CIKernel based fluid dynamics
Swift
26
star
42

SceneKitMaterialEditor

A very simple app for editing SceneKit materials
Swift
26
star
43

DepthOfFieldExplorer

SceneKit Depth of Field Demonstration
Swift
26
star
44

ChromaTouch

Introduction to 3D Touch in Swift with Peek, Pop and Preview Actions
Swift
26
star
45

3D-ReTouch

Experimental Retouching App using 3D Touch
Swift
26
star
46

FurrySketch

Using Apple Pencil's Azimuth & Altitude Data for Creating Directional Furry Brush Strokes
Swift
26
star
47

Purikura

Bulging eyes Purikura effect
Swift
25
star
48

SkyCubeTextureDemo

A demonstration of using MDLSkyCubeTexture in a SceneKit project
Swift
25
star
49

CoreImageConvolutionExplorer

CoreImageConvolutionExplorer
Swift
24
star
50

CIImage-UIImage-Orientation-Fix

Demo of UIImageOrientation to TIFF Orientation conversion that fixes orientation issues when creating CIImage from UIImage
Swift
24
star
51

ImageToneCurveEditor

Project demonstrating the use of CIToneCurve
Swift
24
star
52

PencilSynth

An Audiokit Synthesiser Controller by Apple Pencil
Swift
23
star
53

CoreImageTransitionExplorer

Simple slide show demonstration using Core Image Transitions and PHImageManager
Swift
22
star
54

SceneKitProceduralNormalMapping

Demo of Core Image filter to create SceneKit normal maps from procedural bump maps
Swift
22
star
55

ForceZoom

Zoom Into Image Details using 3D Touch Peek
Swift
21
star
56

PendulaTone

Audio driven by pendulum waves
Swift
20
star
57

Rotatable

Swift Protocol Extension to Rotate any UIView
Swift
19
star
58

PhotoBrowserDemo

A Swift image browser/picker for use with PHImageManager
Swift
19
star
59

Protocol-Extension-Event-Dispatcher

Implementation of EventDispatcher pattern using Swift Protocol Extensions
Swift
18
star
60

ImageProcessingWithMetal

An introduction to image processing with Metal and Swift
17
star
61

WheelTone

Audio synthesis driven by a network of friction gears
Swift
15
star
62

FilterChainingDemo

Demonstration of chaining a series of CIFilters together
Swift
15
star
63

ConvolutionExplorer

vImage / Accelerate convolution filter in Swift
Swift
14
star
64

Bokeh

Demonstration of simulation of hexagonal bokeh using Metal Performance Shaders
Swift
14
star
65

SpriteKitMotionBlur

SpriteKitMotionBlur
Swift
14
star
66

FMNixieDisplay

Nixie Tube Display Component on Swift
Swift
14
star
67

MercurialText

Embossed Type using SceneKit and CIShadedMaterial
Swift
14
star
68

GPUImageDemo

GPUImageDemo
Swift
12
star
69

Christmas-Tree-Bowling

Apple Pencil Controlled Christmas Tree Bowling!
Swift
12
star
70

GestureRecognizer

Demo of custom UIGestureRecognizer
Swift
11
star
71

NumericDialDemo

NumericDialDemo
Swift
11
star
72

ProgSConCompanion

ProgSConCompanion
Swift
10
star
73

CoreImageReactionDiffusion

Gary-Scott reaction Diffusion Implemented as a Core Image CIKernel
Swift
10
star
74

MetalKit-ReactionDiffusion

Reaction diffusion simulation using Metal Kit with parameter gradients controlled by the camera
Swift
10
star
75

PencilScale

Using an Apple Pencil with an iPad Pro as an electronic scale
Swift
9
star
76

GrayScott

Non GPU GrayScott Reaction Diffusion Experiment Using NSOperation
Swift
9
star
77

FMHierarchicalSelector

Hierarchical Selector Component based on UIPickerView & UICollectionView
Swift
9
star
78

NemoCam

Virtual underwater video recording using Filterpedia's Caustic Refraction Filter
Swift
9
star
79

InnerPlanetCurves

Draws Cubic Bezier Curve Between Earth & Venus Using Mercury & Mars as Control Points
Swift
8
star
80

BristlePaint

Embossed Painting with Individual Bristles using SpriteKit Normal Mapping
Swift
8
star
81

StackView

A first play with Swift 2's UIStackView
Swift
8
star
82

MPS_Equalisation

Demonstration of Histogram Equalisation with Metal Performance Shaders
Swift
7
star
83

CoreImageReductionFilterExplorer

App demonstrating extracting color data from CIAreaAverage and displaying Core Image Histograms
Swift
7
star
84

Vertigo

Vertigo inducing colourful painting...
Swift
6
star
85

CoreImageCathodeRayTube

Simple cathode ray tube simulation CIKernel processing live feed from iOS camera.
Swift
5
star
86

Swift3_CoreImageDemo

Swift3_CoreImageDemo
Swift
4
star
87

LondonSwiftDemo

Demo Project for London Swift
Swift
4
star
88

Swarm-Chemistry-GCD

New Version of Swarm Chemistry, using GCD and Bitmap creation
Swift
4
star
89

PHImageManagerTwitterDemo

Demonstration of PHImageManager and Twitter Integration
Swift
3
star
90

CoreImageVoronoi

Full screen animated Moroni noise!
Swift
3
star
91

PhysicsExperiments

Swift
3
star
92

InlineMethodTest

Testing performance of inline code versus instance methods versus class methods
Swift
3
star
93

StPatricksDay

Happy St Patricks Day!
Swift
3
star
94

HisogramSpecificationBlendDemo

Demonstration of Histogram Specification for Image Composition
Swift
2
star
95

SelectorPlayground

Demonstration of `#selector` expression
Swift
2
star
96

FlexMonkeyExamples

Files to support posts in http://flexmonkey.blogspot.co.uk/
Swift
2
star
97

SwiftExperiments

Swift experiments
Swift
1
star
98

Swarm-Chemistry

DEPRECATED: Multithreaded CPU based Swarm Chemistry
Swift
1
star
99

ArraySpeedTest

Some simple tests looking at the performance of different techniques populating and interrogating arrays
Swift
1
star
100

GaussianPlayground

Demonstration of creating a Gaussian blur using separate vertical and horizontal convolution filters.
Swift
1
star