{"id":127,"date":"2011-11-06T01:32:19","date_gmt":"2011-11-06T08:32:19","guid":{"rendered":"http:\/\/new.joyofprocessing.com\/blog\/?p=127"},"modified":"2011-11-06T10:49:16","modified_gmt":"2011-11-06T18:49:16","slug":"googly-eyes","status":"publish","type":"post","link":"https:\/\/joyofprocessing.com\/blog\/2011\/11\/googly-eyes\/","title":{"rendered":"Googly Eyes"},"content":{"rendered":"<p>Today&#8217;s script is a  <strike>shameless ripoff<\/strike> heartfelt homage to Sean Bogg&#8217;s wonderful 2009 artwork, <a href=\"http:\/\/seanboggs.com\/portfolio\/art\/monster.html\">Blue Monster<\/a>.  I thought this would be a great way to demonstrate how to use the transformation matrix in Processing.<\/p>\n<p><script type=\"application\/processing\">\/\/ Processing.js example by Jim Bumgardner\n\nfloat orbit = 6*60*1000; \/\/ 6 minute orbit (in milliseconds)\n\nint nbr_circles = 333;\nfloat deviation = 5\/8.0;\n\nfloat phi = (sqrt(5)+1)\/2 - 1;            \/\/ golden ratio\nfloat golden_angle = phi * TWO_PI;        \/\/ golden angle\n\nfloat gRotate = 0;\nfloat gStickiness = .5;\n\nclass Eye {\n  float x,y,diam;\n  float adj = 0;\n  Eye(float x, float y, float diam)\n  {\n       this.x = x;\n       this.y = y;\n       this.diam = diam;\n       this.adj = -radians(random(15));\n  }\n  void draw()\n  {\n    if (random(180) < degrees(gRotate-adj)*gStickiness) {\n      adj = gRotate;\n    }\n    pushMatrix();\n      translate(x,y);\n      rotate(-adj);\n      noStroke();\n      fill(255);\n      ellipse(0,0,diam,diam);\n      fill(0);\n      ellipse(0,diam*(1-phi)*.9\/2,diam*phi,diam*phi);\n      stroke(255);\n      noFill();\n      arc(0,diam*(1-phi)\/2*.9,diam*phi*.8,diam*phi*.8,TWO_PI-PI\/3,TWO_PI);\n    popMatrix();\n  }\n\n};\n\nEye[] eyes = new Eye[nbr_circles];\n  \n  \nvoid setup_eyes()\n{\n  float lg_rad = width * .47;\n  float lg_area = sq(lg_rad) * PI;\n  \n  float mean_area = lg_area \/ nbr_circles;\n  \n  float min_area = mean_area * (1-deviation);\n  float max_area = mean_area * (1+deviation);\n  \n  float cum_area = 0;\n  \n  float fudge = .87;\n  \n  float hue_incr = frameCount * .0002 + .1;\n  float angle_offset = frameCount * .01;\n  \n  for (int i = 1; i <= nbr_circles; ++i) {\n\n    float angle = i*golden_angle + angle_offset;\n  \n    float ratio = i \/ (float) nbr_circles;\n    float sm_area = min_area + ratio * (max_area - min_area);\n\n\n    float sm_dia = 2 * sqrt( sm_area \/ PI );\n    float adj_sm_dia = sm_dia * fudge;\n  \n    cum_area += sm_area;\n  \n    float spiral_rad = sqrt( cum_area \/ PI );\n  \n    float x = cos(angle) * spiral_rad;\n    float y = sin(angle) * spiral_rad;\n    \n    eyes[i-1] = new Eye(x,y,adj_sm_dia);\n  }\n}\n\nvoid setup()\n{\n  size(500,500);\n  smooth();\n  frameRate(12);\n  setup_eyes();\n}\n\nvoid draw()\n{\n  background(0,85,164);\n\n  gRotate = millis()*TWO_PI\/orbit;\n\n  fill(0);\n  noStroke();\n  pushMatrix();\n  translate(width\/2,height\/2);\n  rotate(gRotate);\n  for (int i = 0; i < eyes.length; ++i) {\n    eyes[i].draw();\n  }\n  popMatrix();\n\n}\n\/\/ END\n\n<\/script><\/p>\n<div class=\"ps_cap\"><a href=\"\/showexample.php?ex=googly_eyes\">source<\/a><\/div>\n<p>I cranked this one out pretty quickly, by building up on previous work.  I started with a copy of the final script from my <a href=\"http:\/\/new.joyofprocessing.com\/blog\/2011\/10\/circles-spirals-and-sunflowers-part-2-2\/\">circles and spirals tutorial<\/a>.  Then I ripped out the code that cycled the colors, and just made it white circles on a blue background, stealing the blue color from my <a href=\"http:\/\/joyofprocessing.com\/showexample.php?ex=flags\/Flag_of_France\">French Flag<\/a>.<\/p>\n<p>Then instead of calculating the positions of the circles in a loop, I moved that code into a new subroutine, called setup_eyes(). This routine does exactly the same calculations, but creates individual eye objects in an array.  Each eye knows its center coordinates and its diameter.  I did this because I knew each eye would have to keep track of its rotation so the pupils can randomly drop, the way googly eyes do.<\/p>\n<p>The drawing loop is now greatly simpler.<\/p>\n<pre>\r\n  pushMatrix();\r\n    translate(width\/2,height\/2);\r\n    rotate(gRotate);\r\n    for (int i = 0; i < eyes.length; ++i) {\r\n      eyes[i].draw();\r\n    }\r\n    popMatrix();\r\n<\/pre>\n<p>pushMatrix() and popMatrix() allow me to use the awesome translate and rotate functions, which transform the drawing space. I translate the center of the coordinate space to the center of the canvas, and then I rotate a little bit.  This is what causes the overall spinning effect.<\/p>\n<p>The rate of spin is controlled by the global variable <i>orbit<\/i>, which says how long it takes to do a full rotation.  This in turn is used to figure out how much I need to currently spin, based on the clock.<\/p>\n<pre>\r\nfloat orbit = 6*60*1000;    \/\/ 6 minute orbit (in milliseconds)\r\ngRotate = millis()*TWO_PI\/orbit;\r\n<\/pre>\n<p>The value gRotate is recomputed each frame of animation, using the current value of millis(), which measures how long the sketch has been running, in milliseconds.<\/p>\n<p>Finally, the draw() method of the Eye class is used to draw each eye.  The basic eye shape is drawn with a white ellipse, a black ellipse, and a little white arc which makes the pupil look shiny.<\/p>\n<pre>\r\n        noStroke();\r\n        fill(255);\r\n        ellipse(0,0,diam,diam);\r\n        fill(0);\r\n        ellipse(0,diam*(1-phi)*.9\/2,diam*phi,diam*phi);\r\n        stroke(255);\r\n        noFill();\r\n        arc(0,diam*(1-phi)\/2*.9,diam*phi*.9,diam*phi*.9,TWO_PI-PI\/2,TWO_PI);\r\n<\/pre>\n<p>This code is bookended by some code that provides the jerky eyeball rotation that appears to be controlled by gravity, just like a real set of googly eyes.  Each Googly Eye keeps track of how much adjustment it needs to make to compensate for the spin.  As the necessary adjustment grows larger, the likelihood that the eye will shift it's position (back to the bottom) increases.<br \/>\nHere's what it looks like:<\/p>\n<pre>\r\n      if (random(180) < degrees(gRotate-adj)*gStickiness) {\r\n        adj = gRotate;\r\n      }\r\n<\/pre>\n<p>The global variable <i>gStickiness<\/i> controls how sticky the eyes are.  I currently have it set to .5.  Lower values will make the eyes travel even further before they adjust.<\/p>\n<p>Then, the <i>adj<\/i> value is used to rotate the individual eye when it is drawn.<\/p>\n<pre>\r\n     pushMatrix();\r\n        translate(x,y);\r\n        rotate(-adj); \/\/ compensate for overall spin so pupil appears on or near bottom\r\n        \/\/ draw eye here\r\n     popMatrix();\r\n<\/pre>\n<p>That's it!  'Til next time, here's looking at you, kids.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s script is a shameless ripoff heartfelt homage to Sean Bogg&#8217;s wonderful 2009 artwork, Blue Monster. I thought this would be a great way to demonstrate how to use the transformation matrix in Processing. source I cranked this one out pretty quickly, by building up on previous work. I started with a copy of the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[11,9,12,13],"class_list":["post-127","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-animation","tag-circles","tag-matrix","tag-spiral"],"_links":{"self":[{"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/posts\/127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/comments?post=127"}],"version-history":[{"count":10,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/posts\/127\/revisions"}],"predecessor-version":[{"id":137,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/posts\/127\/revisions\/137"}],"wp:attachment":[{"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/media?parent=127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/categories?post=127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/joyofprocessing.com\/blog\/wp-json\/wp\/v2\/tags?post=127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}