Category Archives: 11-Lenticular-GIF

Chanamon Ratanalert

03 Feb 2014

So, as I horribly feared, my animated gif turned out terribly in lenticular print form. Not only were the lines too thin to be detected, but also the animation fell apart. I did not anticipate so much motion blur, so the skip from one frame to another is previewed in the first frame and looks terrible. I also, for some reason, didn’t realize that the print would loop if you kept turning it one way, so there’s that.

With a second attempt, I decided that I’ll only deal with transparency, because the fading diamonds were the only parts of my print that looked good. Looking at all the other prints that turned out well or didn’t, I gathered as much as I could about how things printed to try to build a good gif off of that. This is what I found:
– animated transparency: good.
– bright colors: good.
– large jumps between frames: not so good
– thin lines and overlapping opacities don’t translate to print (especially moving lines)
– small movements of multiple small shapes: good (wanfang’s and golan’s)

Going off of these observations, I decided that I wouldn’t go for the clever. I now don’t mind if it’s as blunt as can be, seeing how my abstract thinking isn’t turning out very well. I came up with a bunch of ideas (not pictured here because I’m too lazy to reduce image size so that it’ll upload onto here), but I ultimately fell upon the idea of a flashing light bulb. I could combine the transparency of it glowing with the animation of electricity running through the wires. This idea may seem pretty mundane, but it’s a farther reach for me in terms of working with Processing. The last project, all I did was make geometric shapes and spin them. I didn’t even bother to do the math so that it would loop in 10 frames. This second attempt will require much more exploration, so I’m finding myself okay with needing to redo the print.

lightbulb1-low lightbulb2-low

I’ll be printing the second (black) one.

IMG_20140203_214550357

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
125
126
127
128
129
130
131
132
133
// 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
 
//===================================================
// Global variables. 
 
int     nFramesInLoop = 10; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording;
int bulbColor = 255;
int baseColor = 50;//120; //fill of bulb base
int bkgd = 50;
int sze = 1500;
String  myName = "chanamon";
int j = 0;
 
//cycling through images derived from http://www.openprocessing.org/sketch/96680
int maxImages = 10; // Total # of images == nframesinloop
int imageIndex = 0; // Initial image to be displayed is the first
PImage[] glow_images = new PImage[maxImages]; //for glow sequence images
 
//===================================================
void setup() {
  size (sze, sze);
 
  for (int i = 0; i < glow_images.length; i++){
    glow_images[i] = loadImage("glows" +  nf(i,2)  + ".png");
  }
 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
}
//===================================================
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. 
  renderInner (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;
    }
  }
 
  //change current
  j+=2;
  if (j == nFramesInLoop){
    j = 0;
  }
}
 
//===================================================
void renderInner (float percent) {
  background(bkgd);
  int r = sze/5; //radius
  int d = r*2; //diameter
  int sx = sze/2 - r; //mock origin x
  int sy = 65*3; //mock origin y
 
  imageMode(CENTER);
  image(glow_images[imageIndex],750,750);
  imageIndex = (imageIndex + 1) % glow_images.length;
 
  //bulb
  noFill();
  smooth();
  stroke(bulbColor);
  strokeWeight(15);
  bezier(sx,sy+r, sx,sy+r, sx,sy, sx+r,sy); //left top of circle
  bezier(sx+r,sy, sx+r,sy, sx+d,sy, sx+d,sy+r); //right top of circle
  bezier(sx,sy+r, sx,sy+1.8*r, sx+r/2,sy+1.6*r, sx+.6*r,sy+2.7*r); //bottom left of circle
  bezier(sx+d,sy+r, sx+d,sy+1.8*r, sx+.75*d,sy+1.6*r, sx+d-.6*r,sy+2.7*r); //bottom right circle
  bezier(sx+.6*r,sy+2.7*r, sx+.6*r,sy+2.7*r, sx+.6*r,sy+2.9*r, sx+.8*r,sy+2.9*r); //bottom left curve
  bezier(sx+d-.6*r,sy+2.7*r, sx+d-.6*r,sy+2.7*r, sx+d-.6*r,sy+2.9*r, sx+d-.8*r,sy+2.9*r); //bottom right curve
 
  //threading
  strokeWeight(12);
  fill(baseColor);
  rect(sx+.75*r, sy+3.2*r, r/2, r/2, 95); //bottom round
  rect(sx+.6*r,sy+2.9*r, .8*r, r/3, 25); //first block
  rect(sx+.65*r,sy+3.24*r, .7*r, r/8, 7); //second block
  rect(sx+.7*r,sy+3.37*r, .6*r, r/8, 7); //third block
 
  //wires
  strokeWeight(3.5*3);
  noFill();
  smooth();
  bezier(sx+.9*r,sy+2.9*r, sx+r,sy+1.4*r, sx+r/2,sy+1.8*r, sx+r/2,sy+1.3*r); //left wire
  bezier(sx+d-.9*r,sy+2.9*r, sx+d-r,sy+1.4*r, sx+d-r/2,sy+1.8*r, sx+d-r/2,sy+1.3*r); //right wire
  strokeWeight(8);
  ellipse(sx+r/2,sy+1.3*r, r/10, r/10);
  ellipse(sx+d-r/2,sy+1.3*r, r/10, r/10);
 
  //electricity
  strokeWeight(2.5*3);
  int l = 10*3; //length of electricity segments
  for (int i=0; i < 10; i++){
    line(sx+r/2+(i*l),sy+1.3*r, sx+r/2+(i+1)*l,sy+1.3*r-l);
    line(sx+r/2+(i+1)*l,sy+1.3*r-l, sx+r/2+(i+2)*l, sy+1.3*r);
    i++;
  }
 
  //current - changes with time
  strokeWeight(15);
  stroke(252,210,65);
  line(sx+r/2+(j*l),sy+1.3*r, sx+r/2+(j+1)*l,sy+1.3*r-l);
  line(sx+r/2+(j+1)*l,sy+1.3*r-l, sx+r/2+(j+2)*l, sy+1.3*r);
 
}

Ticha Sethapakdi

01 Feb 2014

Soooo unfortunately my lenticular print turned out kinda NOT AT ALL the way I wanted it to. :(  Which prompted me to make another one! I actually like this one more than my old one, so I guess the print was a disaster for a good cause.

In the interest of allocating enough time to do the things for Project 2, I decided to go with something simple for my second GIF. I found it really funny how we all had to bounce up and down to view each other’s prints, so I decided to create an animation that mimicked that motion.

jigglycube

 

Hopefully it’ll work this time…..

(Made in OpenScad)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
//jigglycube
 
num = 6;
gap = 30;
growthj = 2;
growthi = 1.5;
growthh = 1.5;
 
//fake background fill
translate([-400,300,0]) {rotate([0,90,310]) color("black") {cube([2500,2500,1],center=true);}}
 
//height
for(h = [0 : num]) {
//rows
for(i = [0 : num] ) {
	//columns
	for(j = [0 : num]) {
	color([0.6+4*sin(20*h)/2, 0.6+cos(24*j)/3, 0.6+cos(15*(i+j+1))/4]) {
		translate([-gap*j + j*4.5*cos($t*360)*growthj , 
				  -gap*i + i*5*cos($t*360)*growthi, 
				  gap*h + h*5*sin($t*360)*growthh]) cube(size=gap, center=true);
	}}
}}

Daniel Vu

23 Jan 2014

animation

I ended up rushing this. I had hoped to tweak it a little bit more to make it smoother. Started off with just a squiggle I made up in my sketchbook with the idea that I would use multiple smaller circles to create the design. Programming/code and math not being my forte, I took longer than I should have to figure out how to get the movement the way I wanted.

Negative things I can point out are: not as smooth as I wanted, not a perfect loop, does not end in a complete circle. Positive things: I think the flower-like pattern it creates is nice, the sizing seems to be fine, the offset where it is not symmetrical if split vertically/horizontally without rotating it is kind of cool.

sketch

// 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
// modified by Daniel Vu

int canvas_width = 500;
int canvas_height = 500;
int nFramesInLoop = 30; //change to 10 for lenticular
int nElapsedFrames;
boolean bRecording;

String myName = "danielvu";

void setup(){
size(canvas_width, canvas_height);
nElapsedFrames = 0;
frameRate (nFramesInLoop);
bRecording = false;
}

void keyPressed(){
//press a key to export to the output folder
bRecording = true;
nElapsedFrames = 0;
}

void draw(){
float percentCompleteFraction = 0; //Compute a percentage (0 to 1) representing the current point in the loop
if (bRecording) {
percentCompleteFraction = (float) nElapsedFrames / (float) nFramesInLoop;
}
else {
float modFrame = (float) (frameCount % nFramesInLoop);
percentCompleteFraction = modFrame / (float) nFramesInLoop;
}

render(percentCompleteFraction);

if(bRecording) {
saveFrame("output/" + myName + "-loop-" + nf(nElapsedFrames, 4) + ".png");
nElapsedFrames++;
if (nElapsedFrames == nFramesInLoop){
bRecording = false;
  }
 }
}

void render (float percent){
background(100);
smooth();
noStroke();

fill(0,0,0);
ellipse(canvas_width/2, canvas_height/2, 100, 100);

float cx = canvas_width/2;
float cy = canvas_height/2;
float offset = 50;

for(int i = 0; i < 5; i++){
float offset1 = -(offset/percent);
float angle = (TWO_PI/5) * i;
float px = cx + offset1*cos(angle);
float py = cy + offset1*sin(angle);
ellipse (px, py, 40, 40);
}

for(int j = 0; j < 5; j++){
float newOffset = (offset - 20)/(percent);
float angle2 = ((TWO_PI/5) * j) + 120;
float px = cx + newOffset*cos(angle2);
float py = cy + newOffset*sin(angle2);
ellipse (px, py, 80, 80);
 }
}

 

Lenticular Animation

For my lenticular animation, I thought it would be interesting to work on traditional computational patterns, such as the penrose pattern, generated by an L-system. Printing and having a physical representation of such a pattern is very appealing to me. I started with a simple penrose algorithm and played with different parameters and colors using randomness to derive different patterns. I settled on certain parameters that will make the generated image look like a snow flake.

 

snowflakeg

 

As for my process, I initially had some sketches of different designs and patterns. I found and implemented a few generative algorithms and started varying certain parameters to create patterns I like. Rather than a serial process of drawing a design then implementing, I was constantly sketching different alternatives. Mostly, my sketches were influenced by the output of the algorithms I wrote down. I can’t say that the output was something that I had sketched out initially then implemented, it was a more random and exploratory process. In that sense, the process was largely influenced by the algorithms I was using rather than the other way around.

 

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
 
//===================================================
// Global variables. 
 
int     nFramesInLoop = 30; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording; 
 
String  myName = "mayakreidieh";
 
float[][] nse = new float [5000][2];
 
//===================================================
// Penrose pattern generator
String axiom = "[X]++[X]++[X]++[X]++[X]";
String W = "YF++ZF4-XF[-YF4-WF]++";
String X = "+YF--ZF[3-WF--XF]+";
String Y = "-WF++XF[+++YF++ZF]-";
String Z = "--YF++++WF[+ZF++++XF]--XF";
String F = "";
float step_len = 15*30.0;
int steps = 0;
float theta = radians(36); 
String generated = "";
 
void generate() {
  generated = axiom;
  for (int j = 0; j < 3; j++) {
    String temp = "";
    for (int i = 0; i < generated.length(); i++) {
      char step = generated.charAt(i);
      switch(step) {
        case 'W': temp = temp + W; break;
        case 'X': temp = temp + X; break;
        case 'Y': temp = temp + Y; break;
        case 'Z': temp = temp + Z; break;
        case 'F': temp = temp + F; break;
        default: temp = temp + step; break;
      }
    }
    step_len = step_len * 0.5;
    generated = temp;
    println(generated);
  }
}
void render() {
  translate(width/2, height/2);
  int pushes = 0;
  int repeats = 1;
  steps = (steps + 30) % generated.length();          
  for (int i = 0; i < steps; i++) {
    char step = generated.charAt(i);
    switch(step) {
      case 'F':
        strokeWeight(2);
        stroke(random(200), random(0,100), 255, 40);
        for (int j = 0; j < repeats; j++) {
          line(0, 0, 0 , - (step_len*noise(nse[i][1])*5) );
          ellipse(0,0,10*noise(nse[i][0]),4*noise(nse[i][0]));
          noFill();
          translate( 0 , -step_len);
          nse[i][0]+=2;
          nse[i][1]+=0.01;
        }
        repeats = 1; break;
      case '+': 
        for (int j = 0; j < repeats; j++) {
          rotate(theta);
        }
        repeats = 1; break;
      case '-': 
        for (int j =0; j < repeats; j++) {
          rotate(-theta);
        }
        repeats = 1; break;
      case '[': pushes++; pushMatrix(); break;
      case ']': popMatrix(); pushes--; break;
      case '3': repeats = 3; break;
      case '4': repeats = 4; break;
      default: break;
    }
  }
 
  while (pushes > 0) {
    popMatrix();
    pushes--;
  }
}
 
 
//===================================================
void setup() {
  size(500, 500);
  for (int i=0;i&lt;5000;i++){
   nse[i][0] = random(10); 
   nse[i][1] = random(10); 
  }
  generate();
}
 
void keyPressed() { 
  // Press a key to export frames to the output folder
  bRecording = true;
  nElapsedFrames = 0;
}
 
void draw() {
  background(255);
  render();
 
  // 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;
    }
  }
}

Austin McCasland

21 Jan 2014

golan_good

When I was creating this piece the objective was to magnify the effects of a well-known optical illusion. Each of the horizontal lines in this gif is perfectly parallel to the others, and completely straight. The offset of the boxes gives the illusion of the horizontal lines bending. I thought that adding rotational animation to the illusion would make the lines appear to bend much more and I think in the end it worked fairly well. I created a version that rotated without changing direction and it was a much more powerful illusion, but I was unable to make it work with 10 frames of animation.

 
int     nFramesInLoop = 10; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording; 
 
 
 ////
 int boxHeight, lineWidth;
float speed, testCounter, radius, degrees, rotationSpeed;
boolean leftDirection, rightDirection, clockwise;
String  myName = "golanlevin";
 
//===================================================
void setup() {
  size (1500, 1500); 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
  
  
  ///////
   boxHeight = 60;
  lineWidth =6;
  speed=.5;
  degrees=0;
  rotationSpeed = 2;
  
}
//===================================================
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) {
 
  
  
  background(255);
  fill(0);  
  //This for loop draws the boxes statically.   After everything is set up I would like every other layer
  //to move in an opposite direction.
  if(degrees>5) {
    clockwise = false;
  }
  if(degrees< -5) {
    clockwise = true;
  }
  if(clockwise == true) {
    degrees+=rotationSpeed;
  } else if (clockwise == false) {
    degrees-=rotationSpeed;
  }
  float angle = radians(degrees);
  translate(  (width/2)-(width/(boxHeight+lineWidth)),(width/2)-(width/(boxHeight+lineWidth)));
  rotate(angle);
  
  for(int i=0; i<=height*2+(boxHeight+lineWidth); i+=(boxHeight+lineWidth)) {
   pushStyle();
    stroke (100); 
    strokeWeight (lineWidth); 
    line(-(width), i-(width/2)-(lineWidth/2), width,i-(width/2)-(lineWidth/2));
   popStyle();
   
  }
  for(int i=-(width/2); i<=(width); i+=(boxHeight+lineWidth)) {
    if(abs(((i/(boxHeight+lineWidth))%4)) == 0) {//detects which iteration
      for(int j=-(width/4); j<=(width/2); j+=boxHeight+lineWidth) {
          rect(j*2, i, boxHeight, boxHeight);
      }
    }
    if(abs(((i/(boxHeight+lineWidth))%4)) == 1) {
      for(int j=-(width/4)+2; j<=(width/2); j+=boxHeight+lineWidth) {
        rect(j*2, i, boxHeight, boxHeight);
      }
    }
    if(abs(((i/(boxHeight+lineWidth))%4)) == 2) {
      for(int j=-(width/4); j<=(width/2); j+=boxHeight+lineWidth) {
        rect(j*2, i, boxHeight, boxHeight);
      }
    }
    if(abs(((i/(boxHeight+lineWidth))%4)) == 3) {
      for(int j=-(width/4)-2; j<=(width/2); j+=boxHeight+lineWidth) {
        rect(j*2, i, boxHeight, boxHeight);
      }
    }
  }


  
}

ying_gif

I started with the idea of galaxy, particles and petals, and wanted to create a combination of those. The most interesting experience when creating this piece is that it trains me to think about how each frame is going to be different from other frame. I enjoyed playing with the code. However, I think the coding could still be pushed more to create more varied designs.

image

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
/* OpenProcessing Tweak of *@*http://www.openprocessing.org/sketch/699*@* */
/* !do not delete the line above, required for linking your tweak if you upload again */
// Spiral Galaxy Simulation
// author : Philippe Guglielmetti (Dr. Goulu www.goulu.net)
// 2008.04.03 PhG : my first processing program !
//                  converted from my LUA/Demoniak 3D demo V 1.0
//                  see http://3dmon.wordpress.com/2007/08/26/simulation-de-galaxie-spirale/
// 2008.04.04 PhG : much faster in P3D mode : now ok with 10'000 stars !
//                  keyboard interaction : use arrow keys to alter the galaxy
 
import gifAnimation.*; // http://www.extrapixel.ch/processing/gifAnimation/
 
int     nFramesInLoop = 30; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording; 
 
String  myGalaxy = "galaxy";
 
float pi=4*atan(1);
 
int stars=20000; // only ...
int Rmax=200; // galaxy radius
float speed= 0.4;  //rotation speed
 
// stars follow elliptic orbits around the center
float eratio=.75; // ellipse ratio
float etwist=8.0/Rmax; //twisting factor (orbit axes depend on radius)
 
float []angle=new float[stars];
float []radius=new float[stars];
 
float cx; float cy; //center
 
color col=color(250,93,159); //yellow stars
 
void setup(){
  size(500,500,P3D);
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
 
  background(0); //back to black
  speed=speed/frameRate;
 
  // begin in the center
  cx = width/2;
  cy = height/2;
  // itit stars
  for (int i=0; i&lt; stars; i++){
    angle[i]= random(0,2*pi);
    radius[i]=random(1,Rmax);
  }
  // gifExport = new gifAnimation.GifMaker(this, "galaxy.gif");
  // gifExport.setRepeat(0);	
}
 
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/"+ myGalaxy + "-loop-" + nf(nElapsedFrames, 4) + ".png");
    nElapsedFrames++; 
    if (nElapsedFrames == nFramesInLoop) {
      bRecording = false;
    }
  }
}
 
void renderMyDesign (float percent) {
 
  background(241,255,142); //back to black
  stroke(col);
  for (int i =0; i&lt; stars; i++){
    float r=radius[i];
    float a=angle[i]+speed; //increment angle
    angle[i]=a;
    float x = r*sin(a);
    float y = r*eratio*cos(a);
    float b = r*etwist;
    float x1 = r*cos(b);
//    float y1 = r*eratio*sin(b);
    float s = sin(b);
    float c = cos(b);
    //point(cx1+s*x1,cy+c*x-s*y); //a bit of trigo
    //point(cx+s*x,cy+s*x1-c*y); //a bit of trigo
    //point(cx+s*x,cy+s*x1-c*y); //a bit of trigo
    point(cx+s*x,cy+s*x1-c*y); //a bit of trigo
    //point(cx+s*y,cy1+c*x1-s*y); //a bit of trigo
    point(cx+s*x*6/5,cy+c*x1-s*y); //a bit of trigo
 
//    ellipse(cx+s*x,cy+c*x-s*y, 2, 3);
  }
}

Brandon Taylor

21 Jan 2014

bttaylorMobius

My goal here was to create a Mobius strip generator.  It’s not quite as flexible as I’d like.  You can adjust the twists in the band, but the figure-8 shape is hardcoded.  I’d also hoped to do something more interesting with the coloring to better show the continuity of sides.  I was expecting the 2-D shapes to have a directionality on one side so that viewed from ‘behind’ they would be invisible (I think OpenGL does this?).  Anyway, I couldn’t figure out a good way to have different colored faces on the strip, so I added the balls to make it more dynamic.  I also tried to get the balls to travel along the surface of the strip, but getting the translations right was a nightmare, so I settled for this.  Overall, I like the look of it, but it’s not quite what I’d hoped it would be.

20140121_054541

In fact, the Mobius strip was not my first idea.  I originally wanted to make an infintely zooming/splashing water drop.  When I first thought of it, I was not thinking about doing it programmatically.  Rather than just move on, I wasted some time trying to get a bunch of little particles to act like something like a water drop (alas, I was unable to get far, but I learned that particle collision stuff is tricky).  Next, I thought about trying to program just the shapes of water drops and splash crowns, etc.  I didn’t get very far along there before coming up with an alternative that seemed more feasible.

20140121_054631

 

Code:

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//resolution of mobius strip
int numPoints = 80; //180
//strip width
int stripWidth = 120; //40;
//size of strip
float radius = 600; //200;
//number of twists
int twists = 1;
//adjust twist position relative to loop
float twist_offset = 45.0;
//size of balls
float ball_r = 30; //10;
//number of balls
int ball_cnt = 9;
//speed of balls
int ball_speed = 4;
 
//variables
PVector[] ball_loc;
float ball_ang;
float ang; 
int count = 0;
int saveFrames = 10; //20
 
void setup(){
  size(1500,1500,P3D);
  //size(500,500,P3D);
  ball_ang = 0;
  ball_loc = new PVector[ball_cnt];
  for(int i=0; i&lt; ball_cnt; i++){
    ball_loc[i] = new PVector(0,0,0);
  }
 
}
 
void draw(){
  background(0);
  smooth();
  directionalLight(255,255,255,-1,0,0);
  directionalLight(255,255,255,0,1,0);
  ambientLight(127,127,127);
  translate(width/2, height/2, 0);
  rotateY(2.67);
  rotateZ(-2.43);
 
  //For Selecting orientation
 // rotateY(map(mouseX, 0, width, 0, 2*PI));
 // rotateZ(map(mouseY, 0, height, 0, -2*PI));
 // print("RY: " + map(mouseX, 0, width, 0, 2*PI) + " RZ: " + map(mouseY, 0, height, 0, -2*PI));
 
  //draw strip
  mobius();
 
    //draw balls rotating
    for(int i=0; i &lt; ball_cnt; i++){
      ang = ball_ang + (360/ball_cnt)*i;
      ball_loc[i].set(mobiusCenter(ang));
      pushMatrix();
      pushStyle();
      translate(ball_loc[i].x,ball_loc[i].y,ball_loc[i].z);
      if(ang % 360 &lt; 180){
        color b = color(255-map(ang % 180,0,180,0,255),255 -map(ang%180,0,180,0,255),255);
        fill(b);
      }else{
        color b = color(map(ang % 180,0,180,0,255),map(ang%180,0,180,0,255),255);
        fill(b);
      }
      noStroke();
      sphere(ball_r);
      popMatrix();
      popStyle();
    }
 
  ball_ang += ball_speed;
  if(ball_ang == 720){
    ball_ang = 0;
  }
 
  if(count &lt; saveFrames){
    saveFrame();
    count++;
  }
}
 
void mobius(){
  float angle = 0;
  float angleStep = 180.0/numPoints;
  float twistStep = twists * angleStep / 2;
  float twistAngle = twist_offset;
 
  //translate(200,200,0);
  //noStroke();
  strokeWeight(1);
  beginShape(TRIANGLE_STRIP);
    for(int i=0; i &lt;= numPoints; i++){
      //cycle the colors w/ the angle
      color c = color(255*sin(radians(angle/2)),255-255*sin(radians(angle/2)),0);
      fill(c);
 
      float py = (stripWidth / 2) * cos(radians(twistAngle));
      //raise and lower y to avoid intersection at the middle
      py += sin(radians(angle))*(stripWidth / 2);
      float radiusMod = (stripWidth / 2) * sin(radians(twistAngle));
 
      float px = cos(radians(angle)) * (radius) + cos(radians(angle)) * radiusMod;
      float pz = sin(radians(angle)) * px + sin(radians(angle)) * radiusMod;
      angle += angleStep;
      twistAngle += twistStep;
 
      vertex(px,py, pz);
      py = (stripWidth / 2) * cos(radians(twistAngle) + PI);
      py += sin(radians(angle))*(stripWidth / 2);
      radiusMod = (stripWidth / 2) * sin(radians(twistAngle) + PI);
      px = cos(radians(angle)) * radius + cos(radians(angle)) * radiusMod;
      pz = sin(radians(angle)) * px + sin(radians(angle)) * radiusMod;
      vertex(px,py,pz);
      angle += angleStep;
      twistAngle += twistStep;
    }
  endShape();
}
 
PVector mobiusCenter(float angle){
  float py = sin(radians(angle))*(stripWidth / 2);  //the y off set at the center
  float px = cos(radians(angle)) * radius;
  float pz = sin(radians(angle)) * px;
  PVector p = new PVector(px,py,pz);
  return p;
}
 
PVector mobiusNorm(float angle){
  float px = cos(radians(angle));
  float pz = sin(radians(angle)) * px;
  float angx = atan2(pz,px);
  float angy = twist_offset + twists * (angle * numPoints /180) / 2;
  PVector p = new PVector(angx,angy);
  return p;
}

Haris Usmani

21 Jan 2014

I started out with a totally different idea! I wanted to illustrate the workload of this class (as demonstrated by Prof. Golan in the first lecture) through a Bursting Amoeba. Looks like that didn’t work too well, probably because I just got acquainted with Processing.

Usmani-Notes1

explosion_usmani

Moving on, I thought more about what would look good in the Lenticular Image- this previous GIF has a major ‘jump’ in the last frames so this couldn’t work. Playing with shapes in my head, I thought its was time to appreciate the beauty in nature- I started drafting out a ‘Digital Flower’ that would grow/bloom repeatedly.

Usmani-Notes2

For some reason, I didn’t feel too optimistic about it. I made these flowers when I was ten, I thought- it’s time to move on. So I agreed with that presumption and brain-stormed a little more, that’s when I came up with this.

Note3-usmani

harisusmai_shutter

The Aperture. An integral part of the camera we use everyday- a clever mechanical design that mimics the Iris. The code for this GIF is posted below. I think it came out pretty decent for a first time Processing user, the aperture leaves appear to rotate although its just a bunch of lines moving at the right places.

On my way there, I had to recall my trig and I also came up with a reasonably interesting Optical Illusion.
Focus on the Inner Circle boundary, you’d see the box change size:

illusion_box

Notes4-usmani

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Muhammad Haris Usmani - 1/21/2014
// http://harisusmani.com
 
// Credits to Prof. Golan Levin for Starter Code & Export Frame Option
// http://golancourses.net/2014/assignments/project-1/lenticular-animation/
 
//===================================================
// Global variables. 
 
int     nFramesInLoop = 30; // for lenticular export, change this to 10!
int     nElapsedFrames;
boolean bRecording; 
 
String  myName = "harisusmani";
 
//===================================================
void setup() {
  size (500, 500); 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop); 
}
//===================================================
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;
    }
  }
}
 
//polygon() from http://processing.org/tutorials/anatomy/
void polygon(int n, float cx, float cy, float r)
{
  float angle = 360.0 / n;
 
  beginShape();
  for (int i = 0; i < n; i++)
  {
    vertex(cx + r * cos(radians(angle * i)),
      cy + r * sin(radians(angle * i)));
  }
  endShape(CLOSE);
}
 
//===================================================
void renderMyDesign (float percent) {
 
  //----------------------
  // here, I set the background and some other graphical properties
  background (0,10,30);
  smooth(); 
  stroke (0, 0, 0); 
  strokeWeight (3); 
 
  //----------------------
  // Here, I assign some handy variables. 
  float cx = width/2;
  float cy = height/2;
 
  // Diving Time between Stages:
  float stage1=0.3;
  float stage2=0.5;
  float stage3=0.7;
 
  //----------------------
  // Outer Circles: Static Art
  fill (100); 
  float Big_R=350/2; //Outer Circle Radius
  ellipse (cx, cy, Big_R*2, Big_R*2); //Outer Circle
  //fill (ellipseColor, ellipseColor, ellipseColor);
  fill (80);  
  float R=150; //Inner Circle Radius
  ellipse (cx, cy, 2*R, 2*R); //Inner Circle
 
  float armAngle=0;
  for (int i=0; i < 6; i++) { //Lens Screws in Light Grey
    armAngle=armAngle+60;
    float px = (R-(R-Big_R)/2)*cos(armAngle/180*PI); 
    float py = (R-(R-Big_R)/2)*sin(armAngle/180*PI); 
    fill(180); 
    ellipse (cx+px, cy+py, (R-Big_R)/2, (R-Big_R)/2);
  }
 
  //Dynamic Graphics:
 
  pushMatrix(); 
  translate (cx, cy);
  float radius = 0;
  int nSpokes = 6;
 
  if(percent<stage1) //Stage 1, Say Smile! -- Click
  { 
    radius = 50;
    fill (256, map(percent,stage1/2,stage1,256,0), map(percent,stage1/2,stage1,256,0));
    polygon(nSpokes, 0, 0, radius);
  }
  else if(percent<stage2) //Stage2, Burst Open Shutter
  { 
    radius = (float)map(percent,stage1,stage2,50,130);
    fill (0, 0, 0);
    polygon(nSpokes, 0, 0, radius);
  }
  else if (percent<stage3) //Stage3, Adjust/Focus
  {
    radius = (float)map(percent,stage2,stage3,130,25);
    fill (0, 0, 0);
    polygon(nSpokes, 0, 0, radius);
  }
  else
  {
    radius = (float)map(percent,stage3,1,25,50); //Stage 4, Fine Focus & Loop GIF
    fill (0, 0, 0);
    polygon(nSpokes, 0, 0, radius);
  }
 
  popMatrix();
 
  //-- SHUTTER LEAVES of Exact Length, give Illusion of Rotation 
  float outRadius=sqrt(pow(R,2)-pow((radius*cos(radians(180/nSpokes))),2))-(radius*sin(radians(180/nSpokes))); 
  //Chord Length Formula: http://www.mathopenref.com/chord.html
  armAngle = 0;
  for (int i=0; i < nSpokes; i++) {
    armAngle = armAngle + 360/nSpokes;
    float px = cx + radius*cos(armAngle/180*PI); 
    float py = cy + radius*sin(armAngle/180*PI); 
    fill(255); 
    float disp_x= outRadius*cos((armAngle-360/nSpokes)/180*PI); //Displacement in X
    float disp_y= outRadius*sin((armAngle-360/nSpokes)/180*PI);  //Displacement in Y
    line(px, py, px+disp_x, py+disp_y);
  }
}

Shan Huang

21 Jan 2014

500 x 500 version (60 frames)

1500×1500 version (10 frames)

This lenticular animation is somewhat inspired by this noise wave Processing tutorial. I first tried Processing in the summer two years ago, and I particularly enjoyed playing around with Perlin noise which is the magic to many organic looking generative arts. So for this assignment I wanted to extend the tutorial to render something immersed in water.

I decided to use frog as the subject without much difficulty. The only other candidates were goldfish and jellyfish, whose connection with water seemed a little boringly obvious. I found a cute image of a frog and was thinking about ways to make it look less realistic to match the style of the generated wave. I came to the solution of triangulation and found a triangulation library from processing wiki. With image tessellated into triangles, I now had a collection of vertices and triangles that I could move around with Perlin noise.

In terms of my design process, there are two things worth mentioning. Firstly I stepped the noise parameter of the frog and the wave differently so that the frog appears to be moving slower than the wave. I hoped this could create the illusion that we are looking at the frog through water…. but not sure if it worked. I also adjusted the brightness of the triangles below the wave (again based on Perlin noise) so that it seems like the reflection of the wave casts light onto the frog.

Here’s the image of the frog I used.frog1Here’s another image of a frog that I considered using…

NGS5475 9705

Hmmmm… not so cute as the first one…

Sketches

sketch1

sketch2

sketch3sketch4

Code

import org.processing.wiki.triangulate.*;
 
float xoff = 0.005;
float yoff = 0.005;
float maxWidth = 100;
float maxStrokeWidth = 10;
float minStrokeWidth = 0;
float seed = 0;
float seed1 = 0;
float colorThres = 5;
float waveHeight = 300;
PImage img;
float xScale = 1.4;
float yScale = 1.5;
float xTrans = -80;
float yTrans = 100;
int count = 0;
 
ArrayList triangles = new ArrayList();
ArrayList points = new ArrayList();
ArrayList wavePoints = new ArrayList();
ArrayList imgPoints = new ArrayList();
ArrayList imgTriangles = new ArrayList();
 
void genWavePoints(){
for(int j = 0; j &lt; width+20; j += 20){
PVector newP = new PVector(j, waveHeight);
wavePoints.add(newP);
}
}
 
void genImgPoints(){
imgPoints.clear();
for(int i = 0; i &lt; 1000; i++){
PVector newP = new PVector(random(-50, img.width+50), random(-50, img.height+50));
color newC = img.get(int(newP.x), int(newP.y));
if(alpha(newC) &gt; colorThres){
imgPoints.add(newP);
}
}
 
imgTriangles = Triangulate.triangulate(imgPoints);
}
 
float noiseTranslate(float x, float y, float seed){
return map(noise(xoff*x, seed+y*yoff), 0, 1, y-maxWidth/2, y+maxWidth/2);
}
 
float noiseTranslate(float x, float y, float seed, float maxWidth){
return map(noise(xoff*x, seed+y*yoff), 0, 1, y-maxWidth/2, y+maxWidth/2);
}
 
void setupDesign() {
size(750, 750);
img = loadImage("frog.png");
genWavePoints();
genImgPoints();
}
 
void renderMyDesign(float percentage) {
seed = (percentage &gt; 0.5? (1-percentage) : percentage) * 3;
seed1 = (percentage &gt; 0.5? (1-percentage) : percentage)* 0.75;
 
background(64);
 
noStroke();
fill(255);
beginShape();
for(int i = 0; i &lt; wavePoints.size(); i++){
PVector p = (PVector)wavePoints.get(i);
vertex(p.x, noiseTranslate(p.x, p.y, seed));
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
 
beginShape(TRIANGLES);
 
for (int i = 0; i &lt; imgTriangles.size(); i++) {
Triangle t = (Triangle)imgTriangles.get(i);
noStroke();
PVector imgCenter = new PVector(t.p1.x/3+t.p2.x/3+t.p3.x/3, t.p1.y/3+t.p2.y/3+t.p3.y/3);
PVector center = new PVector(imgCenter.x*xScale+xTrans, imgCenter.y*yScale+yTrans);
PVector p1 = new PVector(t.p1.x*xScale+xTrans, yTrans+t.p1.y*yScale);
PVector p2 = new PVector(t.p2.x*xScale+xTrans, yTrans+t.p2.y*yScale);
PVector p3 = new PVector(t.p3.x*xScale+xTrans, yTrans+t.p3.y*yScale);
float alpha = center.y &gt; waveHeight ? map(noiseTranslate(center.x, center.y, seed), center.y-maxWidth/2, center.y+maxWidth/2, 0, 1.8) : 1;
color c = img.get(int(imgCenter.x), int(imgCenter.y));
fill(int(red(c)*alpha), int(green(c)*alpha), int(blue(c)*alpha), alpha(c));
vertex(p1.x, p1.y &gt; waveHeight? noiseTranslate(p1.x, p1.y, seed1, maxWidth*1.5) : p1.y);
vertex(p2.x, p2.y &gt; waveHeight? noiseTranslate(p2.x, p2.y, seed1, maxWidth*1.5) : p2.y);
vertex(p3.x, p3.y &gt; waveHeight? noiseTranslate(p3.x, p3.y, seed1, maxWidth*1.5) : p3.y);
}
endShape();
 
noStroke();
fill(255, 100);
beginShape();
for(int i = 0; i &lt; wavePoints.size(); i++){
PVector p = (PVector)wavePoints.get(i);
vertex(p.x, noiseTranslate(p.x, p.y, seed));
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
 
}
 
// 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
 
//===================================================
// Global variables.
 
int nFramesInLoop = 120; // for lenticular export, change this to 10!
int nElapsedFrames;
boolean bRecording;
 
String myName = "shanhuan";
 
//===================================================
void setup() {
bRecording = false;
nElapsedFrames = 0;
frameRate (nFramesInLoop);
setupDesign();
}
//===================================================
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;
}
}
}

 

 

Celine Nguyen

21 Jan 2014

Process

In my sketches, I started off with things transforming to other things or some kind of narrative:

Early sketches

I realized that a step-by-step/progressional/narrative-based animation would be difficult to get to loop (especially given our frame limitations). So I spent some time looking at other GIFs (you can see some of my favorites here) and that influenced my decision to do something less concrete and more abstractly geometric.

I really wanted to create something that looped smoothly, and I wanted to figure out how to achieve natural-looking motions. I explored in my sketches some ideas involving a lightbulb and circle shapes, so I decided to combine those ideas and do something a bit more abstract.

I’ve been drawing a lot of lighting fixtures lately, so the circular fan of lines grew from the idea of a chandelier.

 

Result

I went a little crazy with the idea of animating things with a sin function and ended up trying to animate the length of the lines (my initial visual device) but also the background color (to show space being lit up) and the opacity of the lines with the tiny end bulbs (slowly turning on?).

Along the way, I figured out some things I’d definitely like to learn more about:

  • Techniques for smooth color transitions. The background color changes in little jumpy motions.
  • A rate of change for elements that feels more dynamic/variable. I think here the motion of the lines is a bit too regular to feel like an active object, given what I’m trying to do with the changing color.
  • How to have elements smoothly change in proportion to one another. The same sets of lines are the longest/shortest/middle for the entire animation. It would have been interesting to have the sets change in length order (e.g. so the longest lines become the shortest).
  • Trig (and other mathematical bits for cooler transformations and motions). Forgot a ton of it (and also am unfamiliar with a lot of graphical applications).

This was a very useful exercise in terms of orienting myself with Processing and making some forays into motion and color, but I feel the GIF I produced was directed & constrained more by the things I didn’t know and wanted to explore technically. The concept is not as tight as the sketches I drew (and then abandoned). I think it would have benefited from some more consideration of making the motion (of the lines going in and out)  and color change create some sense of a specific, familiar object. It could have been a bit more lightbulb-y or chandelier-y.

Code

int     nFramesInLoop = 10;
int     nElapsedFrames;
boolean bRecording; 
String  myName = "celinenguyen";
boolean debug = false;
int     canvasSize = 500; // 500/1500
int     strokeSize = 2; // 2, 6
int     ellipseSize = 6; // 6, 18

float[] quadrantLength = new float[3];

void setup() {
  size (canvasSize, canvasSize); 
  bRecording = false;
  nElapsedFrames = 0;
  frameRate (nFramesInLoop);
}

void keyPressed() { 
  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, 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) {
  float changingOpacity = sin(percent * (PI * 2)) * 255;
  quadrantLength[0] = 350 * (1 * sin(percent - 0.5)); // 350/1200
  quadrantLength[1] = 300 * (1 * sin(percent - 0.5)); // 300/1100
  quadrantLength[2] = 200 * (1 * sin(percent - 0.5)); // 200/800

  background(#1D1921); // dark purple
  smooth(); 
  strokeWeight (0);
  fill(#1F2638, changingOpacity);
  rect(0, 0, canvasSize, canvasSize);

  if (debug) {
    // displaying percentage
    fill(255);
    String percentDisplayString = nf(percent, 1, 3);
    text (percentDisplayString, 50, 50);
  }

  translate (canvasSize / 2, canvasSize / 2);
  color[] palette = new color[3];
  palette[0] = #E6E3BA;
  palette[1] = #ABA86A;
  palette[2] = #9C9628;
  int paletteIndex = 0;

  float length, x, y;
  fill(255, changingOpacity);

  int quadrantCount = 0;
  for (float i = 0.0; i < (2 * PI); i = i + (PI / 2)) {
    stroke(palette[0], changingOpacity);
    length = quadrantLength[0];
    strokeWeight (strokeSize);
    x = length * cos(i);
    y = length * sin(i);
    line (0, 0, x, y);
    strokeWeight (0);
    ellipse(x, y, ellipseSize, ellipseSize);
  } 
  for (float i = (PI / 4); i < (2 * PI); i = i + (PI / 2)) {
    stroke(palette[1], changingOpacity);
    length = quadrantLength[1];
    strokeWeight (strokeSize);
    x = length * cos(i);
    y = length * sin(i);
    line (0, 0, x, y);
    strokeWeight (0);
    ellipse(x, y, ellipseSize, ellipseSize);
  } 
  for (float i = (PI / 8); i < (2 * PI); i = i + ((2 * PI) / 8)) {
    stroke(palette[2], changingOpacity);
    length = quadrantLength[2];
    strokeWeight (strokeSize);
    x = length * cos(i);
    y = length * sin(i);
    line (0, 0, x, y);
    strokeWeight (strokeSize);
    ellipse(x, y, ellipseSize, ellipseSize);
  } 
}