Jeff’s Lenticular Animation

jeffcrossman-lentloop

 

This lenticular animation was inspired by the oscillation of the balance wheel found within mechanical timepieces. My initial plan was to do a very literal modeling of this mechanic in processing and my initial results were promising. Using a YouTube video that had a slow motion view of the wheel I was able to extract a lot of good detail about the movement, for example, the wheel rotated about 495 degrees before switching directions, and the spring expanded as the wheel moved counter-clockwise and contracted during clockwise movement.

crossman-lenticular-sketch

Once I had the simple harmonic motion working I realized that with the 10 frame limit for Gifpop, there was no way to make a very literal animation of the balance wheel look acceptable. So I went more abstract using what I had as a base for expansion. The animation isn’t very visually complex or compelling so I chose a pop art color palette to make the piece more visually engaging.

Code on GitHub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// This is a template for creating a looping animation in Processing. 
// When you press a key, this program will export a series of images
// into an "output" directory located in its sketch folder. 
// These can then be combined into an animated GIF. 
// Prof. Golan Levin, January 2014 - CMU IACD
// Author: Jeff Crossman
 
//===================================================
// Global variables. 
 
int     nFramesInLoop = 30; // for lenticular export, change this to 10!
int     nScreenResolution = 500; // n X n pixels
int     nElapsedFrames;
boolean bRecording; 
 
String  myName = "jeffcrossman";
 
//===================================================
void setup() {
  size (nScreenResolution, nScreenResolution); 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
  rectMode(CENTER);
}
//===================================================
void keyPressed() { 
  // Press a key to export frames to the output folder
  bRecording = true;
  nElapsedFrames = 0;
}
 
//===================================================
void draw() {
 
  // Compute a percentage (0...1) representing where we are in the loop.
  float percentCompleteFraction = 0; 
  if (bRecording) {
    percentCompleteFraction = (float) nElapsedFrames / (float)nFramesInLoop;
  } 
  else {
    float modFrame = (float) (frameCount % nFramesInLoop);
    percentCompleteFraction = modFrame / (float)nFramesInLoop;
  }
 
  // Render the design, based on that percentage. 
  renderMyDesign (percentCompleteFraction);
 
  // If we're recording the output, save the frame to a file. 
  if (bRecording) {
    saveFrame("output/"+ myName + "-loop-" + nf(nElapsedFrames, 4) + ".png");
    nElapsedFrames++; 
    if (nElapsedFrames == nFramesInLoop) {
      bRecording = false;
    }
  }
}
 
//===================================================
void renderMyDesign (float percent) {
 
  // This is an example of a function that renders a temporally looping design. 
  // It takes a "percent", between 0 and 1, indicating where we are in the loop. 
  // This example uses two different graphical techniques. 
  // Use or delete whatever you prefer from this example. 
  // Remember to SKETCH FIRST!
 
  //----------------------
  // here, I set the background and some other graphical properties
  background (0, 153, 255); 
  stroke (229, 6, 123); 
  fill(0, 0, 0);
  strokeWeight (42); 
  smooth();
 
  //----------------------
  // Here, I assign some handy variables. 
  float amplitude = radians(55);
  float period = 240;
  float x = amplitude * cos(TWO_PI * percent);
 
  if (x > radians(45))
    x = radians(45);
  else if ( x < -radians(45))
    x = -radians(45);
 
  //text (x, 200, 20);
 
  scale(nScreenResolution / 500);  // Scale drawing to screen size
 
  translate(250, 250);
  rotate(-radians(percent*90));
  translate(-250, -250);
 
  pushMatrix();
  translate(250, 250);
  rotate(x);
  rect(0, 0, 100, 100);
  popMatrix();
 
  pushMatrix();
  translate(151, 151);
  rotate(-x);
  rect(0, 0, 100, 100);
  popMatrix();
 
  pushMatrix();
  translate(349, 151);
  rotate(-x);
  rect(0, 0, 100, 100);
  popMatrix();
 
  pushMatrix();
  translate(349, 349);
  rotate(-x);
  rect(0, 0, 100, 100);
  popMatrix();
 
  pushMatrix();
  translate(151, 349);
  rotate(-x);
  rect(0, 0, 100, 100);
  popMatrix();
}