"IMPERFECTION" IN ANIMATION is a good thing

Good article:


IMPERFECTION IN ANIMATION by Tom Gasek -
http://www.stopmotionworks.com/articles/imperftanim.htm


Written with reference mainly to traditional stop-motion animation vs. CG ,  but the points are equally valid for hand-drawn vs. CG.


In the constant push to learn new software there develops this illusion in many beginning student's minds that the software is what will really do it for them,  that's what is really important.   They lose sight of animation as an expressive art , that shows the hand of the artist.


(click the image to see image larger)







(*some might say that the high-standard set by animators like Milt Kahl, is "perfection" in animation ,  but it's a skillful illusion-of-perfection, the "illusion of life"  , not a slavish reproduction of realism , because there is enough artistic license and graphic "cheats" in these drawings to keep them from looking too perfect, too realistic.   The human hand of the artist is evident.  There is a warmth and appeal to the drawings that we respond to as humans.)

This is in no way to denigrate the skill level it takes to do appealing, warm CG animation.   If anything the CG animator has the greater task to avoid having the animation look "too perfect".

Vector Math + Colors + Symmetry





This code uses OOP, Loops, and PVectors. Use the arrow keys to change the settings while the app is running.



import processing.opengl.*;
import processing.opengl.*;

Worm[] w;

int num_worms = 5;
int worm_length = 20;

void setup() {

size(512, 512, OPENGL);
smooth();
noStroke();

// color mode as HSB so we can cycle through the color wheel
colorMode(HSB, 360, 255, 255);

reset();
}

void reset() {
w = new Worm[num_worms];
for (int i = num_worms-1; i >= 0; i--)
w[i] = new Worm( worm_length, 20 );
}


void keyPressed()
{
switch (keyCode) {

case 38 : // up
num_worms++;
break;

case 40 : // down
num_worms--;
if (num_worms <= 0)
num_worms = 1;
break;

case 37 : // left
worm_length--;
if (worm_length <= 0)
worm_length = 1;
break;

case 39 : // right
worm_length++;
break;
}
reset();
}


void draw() {

background(40);

// radius of structure
float rad = dist(mouseX, mouseY, width/2, height/2);

// angle between each worm
float angle = TWO_PI / w.length;

// get the mouse angle from center for rotation
float mouse_angle = atan2(mouseY-height/2, mouseX-width/2);

// loop through each worm and distribute them in a circle
for (int i = 0; i < w.length; i++) {

float dx = width / 2 + rad * cos(angle * i + mouse_angle);
float dy = height / 2 + rad * sin(angle * i + mouse_angle);

// create new force from circle code
PVector force = new PVector( dx - w[i].p.x , dy - w[i].p.y );

// mult force so it's not so extreme. Try changing this value!
force.mult( 0.2 );

w[i].v.add(force);
w[i].draw();
}
}




class Worm {

PVector p, v;
PVector[] trails;

color c;
float hueCycle = 0;
float fatness = 20;

Worm( int _length, float _fatness )
{

p = new PVector(width/2, height/2); // position
v = new PVector(); // velocity

fatness = _fatness;

// setup trails by placing them randomly
trails = new PVector[_length];
for ( int i = trails.length-1 ; i >= 0; i--) {
trails[i] = new PVector( random(width), random(height) );
}
}


void draw()
{
// drag. Try changing this!
v.mult( 0.85 );

// add the velocity to the position
p.add( v );

// update trails
// set first trail to be the object we're tracing
trails[0].x = p.x;
trails[0].y = p.y;

// loop through the trails array from LAST to FIRST
// setting each vectors position to the previous one
for ( int i = trails.length-1 ; i >= 1; i--) {
trails[i].x = trails[i-1].x;
trails[i].y = trails[i-1].y;
}


// cycle colors
hueCycle -= 5 ; // cycle speed. Try changing this!
while (hueCycle < 0 ) {
hueCycle += 360;
}

for ( int i = trails.length-1 ; i >= 0; i--) {

// loop through curHue
float curHue = hueCycle + i * 5f;
while (curHue > 360 ) {
curHue -= 360;
}

// create new color from hue cycle
c = color(hueCycle, 255, 255);
float weight = (float) i / trails.length;
float wave = sin(weight * PI);
float size = (wave * fatness);
fill( curHue, 255, 255 );
ellipse(trails[i].x, trails[i].y, size, size);
}
}
}

Source for this project: http://media.quilime.com/?p=src/processing/vector_worms/

BAVC Open Labs [Blue Lab]

For the week of Spring Break (March 28th - April 1), there will be Open Labs.

Tuesday, Wednesday, Thursday - 12-6pm

Vectors 101, in Processing

What is a Vector?


In short, we use Vectors when we want to move something. When describing the placement of an object in space, we're familiar to specifying the position with variables, such as x, y, and z. These location variables become inherent to any object that we want to move. In code, the word Vector has a few meanings, but in this case it simply means a collection of values that describe a position in space. In Processing, a Vector is simply an object that already contains x, y, and z variables for moving things around. Simple, but very powerful! In using Vectors you are opening the door to the entire realm of Vector Math. But, for now, it's let's just think of a Vector as a collection of spacial values for you to use when it's appropriate. Processing has a Vector object built in, called the PVector. There is an excellent tutorial on Vectors by Daniel Shiffman on Processing.org




Why are Vectors useful?


They're useful because they allow you to store position variables in ONE variable, rather than 2 (or 3). It can code easier to think about, and you're able to use built-in functions that come with Processing.

For example:

Let's say we're creating a thing that's moving through space. That object may contain the variables:

float x, y, xspeed, yspeed;

It would be much more convenient to just have position and speed as their own variables. With vectors, we can do that.

PVector position, speed;

In order to access the x, and y values from the PVector, we can get to them by using the DOT syntax:

position.x = 50;
position.y = 20;
speed.x = -1;
speed.y = 0.5;

Example of code written with x and y values. This example is a Ball that follows the Mouse.



// position
float x,y;
// velocity
float vx,vy;

void setup() {
size(512,512);
x = 10;
y = 10;
}

void draw() {

background(40);

// add velocity to the vector by subtracting the current position
// from the mouse position
if (mousePressed) {
vx = mouseX - x;
vy = mouseY - y;
vx *= 0.2;
vy *= 0.2;
}

// adding the velocity vector to the position vector
x += vx;
y += vy;

// multiplying the velocity to "dampen" it
vx *= 0.8;
vy *= 0.8;

// draw
fill(255);
ellipse(x,y,40,40);
}

The same code written with a Vector to handle the velocity and the position variables:



// position
PVector pos;
// velocity
PVector vel;

void setup() {
size(512,512);
pos = new PVector(width/2, height/2);
vel = new PVector();
}

void draw() {

background(40);

// add velocity to the vector by subtracting the current position
// from the mouse position
if (mousePressed) {
vel.add(new PVector((mouseX-pos.x), (mouseY-pos.y)));
vel.mult(0.1);
}

// adding two vectors
pos.add(vel);
vel.mult(0.9);

fill(255);
ellipse(pos.x, pos.y, 40, 40);
}

Notice we're using Object Oriented Programming techniques when we're using the PVector object. Because, quite simply, it's a Class just the same as you would defined yourselves. You could potentially craft your own Vector class if you wanted. So, in using PVector we need to use the 'new' keyword every time we create a new instance, just as if it was a normal object of any other class.

Inside the class folder under '_examples' are examples of how to use Vector class.

You can also find them here: Vectors

Calculating Circle Intersections with Vectors



Circle c1, c2;

void setup()
{
size(600, 300);
strokeWeight(2);
smooth();

c1 = new Circle( 400, 150 );
c2 = new Circle( 400, 150 );
}


void draw()
{
background(150);

c2.pos = new PVector( mouseX, mouseY );

// fluctuate radius with sin()
c1.radius = ((sin(frameCount / 30.0) + 1) / 2 * 75) + 25;

// calculate intersection by comparing distances between Circles
if (c2.pos.dist(c1.pos) < c2.radius + c1.radius) {
stroke(200,0,0);
} else {
stroke(0);
}

// point at opposing circle
c1.pointAt(c2.pos);
c2.pointAt(c1.pos);

// draw
c1.draw();
c2.draw();
}


class Circle
{
PVector pos;
float radius = 100;
float theta = 0;

Circle( float _x, float _y ) {
pos = new PVector(_x, _y);
}

void draw()
{
noFill();

// ellipse
ellipse( pos.x, pos.y, radius * 2, radius * 2 );
point( pos.x, pos.y );

// angle
pushMatrix();
translate(pos.x, pos.y);
rotate( theta );
line(0, 0, radius, 0);
popMatrix();
}

void pointAt(PVector p)
{
theta = atan2(p.y - pos.y, p.x - pos.x);
}
}
More examples of the smoothness of movement by using a velocity vector to ease-in the object.Source code for all examples in this post: Vectors.tar.gz

Friday Inspiration: Frédéric Back and others

Here are some videos to inspire you as we go into the weekend and next week's Spring Break .    I came across these inspirational videos and links on Dan Caylor's "ON ANIMATION" site recently.    These are all too good not to share, so I'm reposting them here.

Frédéric Back is one of our greatest living animators and film makers.    He is perhaps best known for his 30-minute tour de force "The Man Who Planted Trees" .    If you do not know this film I highly recommend you get the DVD set  "The Man Who Planted Trees DVD Box Set - Nine Animated Classics by Frederic Back"

In this recent interview, Daisuke Tsutsumi interviews Frédéric Back about his life, passion, and contribution to SketchTravel. (see sketchtravel.com  for more information)


SketchTravel - Frederic Back from Curio on Vimeo.

Part 1 of "The Man Who Planted Trees" -



------------

Next , illustrator and character designer Wouter Tulp demonstrates his drawing process:


Character sketch from Wouter Tulp on Vimeo.

http://theartcenter.blogspot.com/2011/02/wouter-tulp-sketching-character.htm




-------------

Finally, here is a wonderful blog of life drawings from current and former employees of Aardman Animation, Bristol, UK   -



http://aardlife.blogspot.com/

drawing by Aardman Animation artist Ashley Boddy
(click on image to see it larger)

Junkyard Jumbotron



Junkyard Jumbotron from chris csik on Vimeo.


The Junkyard Jumbotron lets you take a bunch of random displays and instantly stitch them together into a large, virtual display, simply by taking a photograph of them. It works with laptops, smartphones, tablets --- anything that runs a web browser. It also highlights a new way of connecting a large number of heterogenous devices to each other in the field, on an ad-hoc basis.

Creating Javascript Bookmarklets

Javascript "Bookmarkets" are mini applications that are run form your browsers bookmark menu. When you click them, they don't actually take you to a url, but they run code instead. Bookmarklets can be used for a number of purposes. They can:

  • Pass data from the current site to another url
  • Modify the current page by addding/removing/changeing elements
  • Work behind the scenes, like clearing your cookies or setting preference

We recently saw Kathack.com, which introduces a Katamari ball to the website you're on, which uses a bookmarklet to initiate the script. Bookmarklets can be used as games, tools, or services. Here's some examples:

Bookmarking:

Tools:
  • Sprite Me computes all images on the page into css sprites
  • Readability makes websites more readable (extension)
  • Darken darkens the website you're on.

Games: (cool!)
  • Asteroids destroy the current webpage with a spaceship
  • Katamari Hack mess up the page with a Katamari Ball (previously posted)
  • Url-Hunter an entire game played in the address bar (not really a bookmarklet, but it is javascript)
  • Marklets Game simple game where you knock-out bookmarks.


How to start


The first thing you need to know is that when you make a bookmarklet, you prepend javascript: to the beginning of the href of the link, like so:
<a href="javascript: alert('Hi There!');">Marklet</a>

run this code

Use an Anonymous Function as Code Wrapper


Because there is probably javascript running on the page you're on, it's necesarry to create your own scope so you don't have any colissions with variables you define in your code. Wrapping your code in an anonymous function allows you to define any variables you need and runs your code in its own CONTEXT. A context implies that the code only knows about itself, or any variables you explicitely send to it.

javascript:(function(){ alert('My Code'); })();

run this code

As you can see, it can get pretty tricky to write javascript in one line, but it's not necesarry. You can split up your code into multiple lines, and then run it through a minifyer. Putting your code into this JS Minifyer will condense it to a single line.

Remote Source Code


Sometimes it's easier to store your javascript on your own server. In our case, we'll use our own foloders on the BAVC servers. Then, our bookmarklet loads our javascript from our server and inserts it into the page. Therefor, your bookmarklet might look like this:

javascript:
var i, s,
sc = [ 'http://instructors.bavc.org/gdunne/marklet.js'];
for ( i in sc ) {
s = document.createElement('script');
s.src = sc[i];
document.body.appendChild(s);
}
void(0);

And, after it's been minified:
javascript:var i,s,ss=['http://instructors.bavc.org/gdunne/marklet.js'];for(i in ss){s=document.createElement('script');s.src=ss[i];document.body.appendChild(s);}void(0);

Let's go over what this code is doing. The most important is the ss variable, which is an array of scripts that you want to add to the page. Then, we loop through this array and create <script> elements document.createElement('script');, and append them document.body.appendChild(s) to the current document. If there's any initialization functions in those scripts, they will be run as soon as they are added to the page. We could also include a number of scripts by adding to the sc[] array. Say, if we needed jQuery, we could just add a link to it like so:

javascript:
var i, s,
sc = [
'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
'http://instructors.bavc.org/gdunne/marklet.js'
];
for ( i in sc ) {
s = document.createElement('script');
s.src = sc[i];
document.body.appendChild(s);
}
void(0);

Note, that we add it before our script so we're sure it's available when our code runs.


So, let's make one!


Some bookmarklet examples. You can just copy and paste these into a URL to test them.

Change the current background color:

javascript:void(document.bgColor = prompt(' Type a hex color, like #4545f5, or just type one.', 'red' ));

run this code

This may not work on this current blog as bgColor is depricated, so try copying that code and running it on another, simpler website as an example.

In this code we prompt the user to fill in the background color, and when they reply, we set the documents background color to their response. bgColor is actually a depricated function, but it's used for the sake of example. A cleaner way would be to include another library, like JQuery.

However, if we include jquery remotely, we might as well store our script remotely instead of coding it into the bookmarklet itself. This makes development easier because then if anyone else has installed your bookmarklet, they are retrieving your code from your server, keeping the program up to date.

Include Jquery and run a script from a remote server that uses jquery to modify the page.

javascript:
var i, s,
sc = [
'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js'
, 'http://media.quilime.com/files/src/js/marklet.js'
];
for ( i in sc ) {
s = document.createElement('script');
s.src = sc[i];
document.body.appendChild(s);
}
void(0);

run this code

The above script includes Jquery and then includes my javascript from my own server. The source of marklet.js is:
// test bookmarklet
(function(){

$('*').css({
'font-size' : '11px'
, 'font-family' : 'monospace'
, 'background-color' : '#232323'
, 'color' : '#00ff00'
});

})();

...which turns the current page into hacker l33t style.

Next Steps

Spend some time getting familiar with creating bookmarklets, and then create a few that modify the current page. Then when you're getting comfortable with the inline coding inside a bookmarklet, try including a remote script from your BAVC folder. What will your bookmarklet do?

Resources: http://fmarcia.info/jsmin/test.html

Google Field Trip Recap


Photo by kingobie1 via flickr

We were given a tour of the Google campus in Mountain View by Ellen Ko, who is involved in the Google Open Source office. We got tour of Building 43 and its neighbors, and had lunch with Jun Hamano (programmer on the GIT project) and Ian Hickson (spec writer for the HTML5 spec).

View more pictures of our trip on Oba's photostream:


Katamari Website Hack



Katamari Hack is a bookmarklet that turns any web page into Katamari Damacy. Paste the below code into the url bar of any website, or click this link, to try it out.


javascript:var i,s,ss=['http://kathack.com/js/kh.js',
'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js'];
for(i=0;i!=ss.length;i++){s=document.createElement('script');
s.src=ss[i];document.body.appendChild(s);}void(0);


This was the winner of the 2011 Yahoo HackU contest at University of Washington.

From the developers website:

How does it work?


Short version: css transforms (for things stuck to the katamari), canvas (drawing the katamari), and z-index (illusion of depth).

Long version: The bookmarklet loads jQuery and kh.js into the current page. jQuery is used mostly for .offset() and .css(). kh.js is where all the action happens:

  • Splits all the text on the page into words/spans. (StickyNodes::addWords)
  • Builds a grid data structure so that intersections with elements can be found quickly (StickyNodes::finalize). Essentially grid[floor(x / 100)][floor(y / 100)] is a list of elements in a 100x100 pixel block. This should probably be an R-tree, but the hot-spot in this program is definitely in the rendering.
  • The ball and stripes are drawn in a canvas that gets moved around the page (i.e. position: absolute; left: x; top: y;). See PlayerBall::drawBall.
  • When an element is attached to the katamari, a clone is made. The original element is hidden. The new element is moved around by setting -webkit-transform. The transform rotates the element about the rolling axis of the katamari and scales the element to make it look like it's coming out of the page. See PlayerBall::drawAttached, transform_test.html, and transform_test2.html.

PI is Wrong!



An entertaining math excursion about PI.

Digital Pathways Job Readiness Workshop


Bavc will be holding a Job Readiness workshop!


Digital Pathways
Job Readiness Workshop
Tuesday, March 22nd 2011
@ BAVC inside the MPR
5:00pm - 7:30pm

Inspiration: Pencil Tests - deleted scenes from Snow White

 During the making-of Walt Disney's  "Snow White and the Seven Dwarfs" several sequences were started and then abandoned due to story changes or pacing issues.

Walt made the difficult decision to cut sequences that had already been completely animated , for the good of the overall pacing of the film.   Fortunately for us the Disney Studio preserved the original drawings and the pencil test footage so we can view these "lost" scenes :

The Soup Sequence -  (Dwarfs animated mainly by Ward Kimball,  with some scenes by Fred Spencer, Bill Tytla, Marvin Woodward, Dick Lundy and Bill Roberts. Snow White animated by Grim Natwick)




Here's the link to see the Bedroom Fight Scene between Grumpy and Doc (Dwarfs animated by Fred Moore , Snow White animated by Grim Natwick , with a couple of scenes of Snow White animated by Jack Campbell) .  Embedding is disabled , so you'll have to click through to YouTube to watch it:


Bedroom Fight sequence Pencil Test -- CLICK HERE to view --

Computational Columns



This work by Michael Hansmeyer is the result of software created in Processing. He developed a mathematical algorithm to subdivide and distort the faces of a 3D model of a traditional Doric column into a complex and crystalline forms. The software then slices the 3D model and cuts each plane on a laser cutter. The columns can indeed support weight, and are made without glue. This fabrication design is a unique progression of digital computer-aided methods when creating architectural and sculptural forms.




Hansmeyer's column stands nine feet tall, weighs about 2000 pounds, and is made out of 2700 1mm-thin slices of cardboard stacked on top of wooden cores. It contains somewhere between 8 and 16 million polygonal faces -- too complex for even a 3D printer to handle, according to Hansmeyer. "Every 3D printing facility we spoke to turned us down," he tells Co.Design. "Typically those machines can't process more than 500,000 faces -- the computer memory required to process the data grows nonlinearly, and it also gets tripped up on the self-intersecting faces of the column."

Slideshow on Fast Code Design

Project Page

Continuum - Computational Fashion



"Continuum" is software fabrication project by Mary Huang, past student of Design | Media Arts at UCLA, and Interaction Design at CIID. The project blends rapid fabrication, interactive software, and the accessibility of the web, to let individuals participate directly in the design and production process.

The software is developed in Processing and allows you to design a dress and convert it into a 3D model, which is turned into a flat pattern that can be cut out of fabric and sewn into the dress. The physical dress be purchased through the fashion label, but also the cutting patterns will be downloadable for those who would rather make it themselves in the material of their choice.

There is also a web-based application created using Processing.js which allows you to create a dress online. The future iterations will also include ability to save your measurements, create and save designs, purchase the physical dress, or download the cutting pattern for their design.





Project Page

via: http://www.creativeapplications.net/processing/continuum-processing/