Using p5*js, use the canvas to create an animated artwork. In our tutorials, we have seen two different ways of approaching animation and movement in p5. Many of you will find it convenient to choose one or the other, but both approaches can be combined in interesting ways as well.
In both cases, you should aim to use coding elements which support your artistic vision, integrating elements from this module with the previous module. You do not need to use all of these, but you will likely use three or four from each module. What I am most interested in is that you have created a compelling animated sketch that evidences two weeks of work. As a review:
Module 1: Generative art
variables
simple 2D shapes
complex shapes with beginShape(), endShape(), and either vertex() or curveVertex()
for loops
-- index style (where the for loop variable increments by one)
-- drawing element style (where the for loop variable increments by some amount that is useful to a drawing operation)
nested for loops
randomness
noise
if/else conditional statements
Module 2: Animation and Movement
changing variables with +=, ++, etc.
using noise() with frameCount to fluidly change the output
opacity/transparency (either in background or stroke/fill to create different effects)
images
-- textured images with tint() and filter()
-- sprite animations or characters
sinusoidal movement
-- drawing in a circular fashion with sin() and cos()
-- drawing in a spiral fashion with sin() and cos() and a changing radius
-- moving elements in a sine wave fashion with sin() and a changing angle input
"LFO" (low frequency oscillator) modulation of animation loops (a slower loop that modifies the speed of the first loop)
interactivity
-- from keyboard input
-- from mouse input
arrays
Gamelike or Narrative "Tableau"
The first is closer to what we think of when we hear the word "animation": a scene with a background and foreground which either plays automatically (more scene or narrative adjacent) or is activated by interactivity (more game like).
Your project does not need to (and probably should not) aim to create an entire narrative or playable game with win and lose conditions. This is what is meant by "tableau". Aim instead to create something that gestures towards that: in the case of the narrative scene, maybe you are setting the scene just before the story starts. In the case of the interactive element, you may aim to have a convincing and satisfying interactive behavior that moves a character along.
Generative Art Moving "Tableau"
You may elect to continue working in a more geometric and visually abstract fashion as we saw in the first project, except this time your work will require motion. This time you should not use noLoop() as we want for your composition to change over time. In this approach, you may any and all of the techniques described above to create movement, including interactivity, changing variables linearly (+,-, for example), animation loops, LFOs, sine wave or circular movement, translate, rotate, etc. The difference is primarily that you are not trying to render a scene, but working with shapes (or images!) to create a more abstract visual.
Homework
Examples
let rows = 40;
let noiseScale = 0.007; //
let noiseSpeed = 0.01;
function setup() {
createCanvas(600, 600);
noiseSeed(1); // stabilize the noise field -- everytime we get the same results from noise
}
function draw() {
background(220);
let yd = height / rows;
let xd = width / rows;
for (let x = xd / 2; x < width; x += xd) {
for (let y = yd / 2; y < height; y += yd) {
let w =
noise(x * noiseScale, y * noiseScale, frameCount * noiseSpeed) * xd; // plug in up to 3 values, returns avalue betwen 0 -1
circle(x, y, w);
}
}
}
let noiseScale = 0.007; //
let noiseSpeed = 0.01; //
function setup() {
createCanvas(600, 600);
noiseSeed(1); // stabilize the noise field -- everytime we get the same results from noise
angleMode(DEGREES); // default mode angles is RADIANS
}
function draw() {
background(220);
translate(width / 2, height / 2);
let r = 50;
let points = 100;
beginShape();
for (let a = 0; a < 360; a += 360 / points) {
let n = map(
noise(a * noiseScale, frameCount * noiseSpeed),
0.1,
0.9,
0.5,
1
);
let x = sin(a) * (r * n); // sin and cos return values between -1 and 1
let y = cos(a) * (r * n);
vertex(x, y);
}
endShape(CLOSE);
}
let noiseScale = 0.007; //
let noiseSpeed = 0.005; //
let tx, ty; // translation coordinates
let ra = 0; // rotation angle
let bgA = 0; // angle for sin movement between bg colors
let bgc1, bgc2;
let maxRadius = 400;
function setup() {
createCanvas(600, 600);
noiseSeed(1); // stabilize the noise field -- everytime we get the same results from noise
angleMode(DEGREES); // default mode angles is RADIANS
tx = width / 2;
ty = height / 2;
bgc1 = color("#E91E63");
bgc2 = color("#1EE9E0");
}
// interrupts the draw loop
function mousePressed() {
tx = mouseX;
ty = mouseY;
maxRadius = 0;
}
function mouseDragged() {
tx = mouseX;
ty = mouseY;
}
function draw() {
if (maxRadius < 400) {
maxRadius++;
}
let bgLerp = map(sin(bgA), -1, 1, 0, 1); // sin returns between -1 and 1
bgA += 0.1;
let bg = lerpColor(bgc1, bgc2, bgLerp);
bg.setAlpha(1); // sets the transparency of the color
background(bg);
// translation
translate(tx, ty);
tx += 0.5;
ty += 0.7;
if (tx > width * 2 && ty > height * 2) {
tx = -width / 3;
ty = -height / 3;
}
//rotation
rotate(ra);
ra += 0.2;
noFill();
strokeWeight(5);
let points = 15;
for (let r = 10; r < maxRadius; r += 3) {
let s = map(r, 10, width, 0, 1);
let c = lerpColor(color("#9C27B0"), color("#00BCD4"), s); // interpolates between two colors by a factor between 0 and 1
stroke(c);
beginShape();
for (let a = 180; a < 360; a += 360 / points) {
let n = map(
noise(a * noiseScale, r * noiseScale, frameCount * noiseSpeed),
0.1,
0.9,
0.5,
1
);
let n2 = map(
noise(a * noiseScale, r * noiseScale, 1000 + frameCount * noiseSpeed),
0.1,
0.9,
0.5,
1
);
// let n = 1;
// let n2 = 1;
let x = sin(a * n) * (r * n2); // sin and cos return values between -1 and 1
let y = cos(a * n2) * (r * n);
vertex(x, y);
}
endShape();
}
filter(BLUR);
}
let img1, img2; // variables that will hold my images
let a = 0; // angle of rotation of our icon
let noiseScale = 0.006; // smooth out our noise values
let x = 200;
let y = 200;
let lerpFactor = 0.01; //
let hoverA = 0; // angle for our sin() to create a left and right hover
let amp = 20;
let s = 1; // scale factor of img1 AND img2 that grows and shrinks with the two mousePress States
function preload() {
img1 = loadImage("/assets/p5img/smiley1.png");
img2 = loadImage("/assets/p5img/smiley2.png");
}
function setup() {
createCanvas(500, 500);
imageMode(CENTER); // allows to adjust how image() interprets x y coordinates. CENTER will interpret x and y as the center
angleMode(DEGREES); // defaults RADIANS: 0 - (2 * 3.14)
// DEGREES 0-360
}
function draw() {
if (mouseIsPressed == false) {
background(0);
// variable scope -- local scope declaration
let xOffset = sin(hoverA) * amp; // this variable is only usable inside this if clause
translate(x + xOffset, y);
x = lerp(x, mouseX, lerpFactor);
y = lerp(y, mouseY, lerpFactor);
let d = dist(x, y, mouseX, mouseY);
let n = noise(x * noiseScale, mouseY * noiseScale, d * noiseScale); // noise gives 0-1 -- it's actually 0.2 - 0.8
a = map(n, 0.2, 0.8, 0, 360); // ??? whats the range of rotation???
//
rotate(a);
scale(s); // when scale gets value, it just interprets it like a positive value
image(img1, 0, 0);
// a+=0.1; // adding gives us a constant rotation in one direction.
hoverA++;
if (s>1){
s-=0.05; // shrink or scale down the image
}
}
else {
background(0,10);
let xOffset = random(-s*6,s*6);
let yOffset = random(-s*3,s*3);
translate(mouseX+xOffset,mouseY+yOffset);
scale(s);
image(img2, 0, 0);
s+=0.1;// scale up the image
}
}
let minR = 10;
let maxR = 200;
let dR = 10; // difference between radii
let col1, col2;
let noiseScale = 0.005;
function setup() {
createCanvas(400, 400);
col1 = color("rgb(121,124,245)"); //
col2 = color("rgb(189,109,189)");
noStroke();
angleMode(DEGREES); // 0 - 360
}
function draw() {
background("rgb(127,205,255)");
for (let r = maxR; r > minR; r -= dR) {
let cI = map(r, maxR, minR, 0, 1);
let c = lerpColor(col1, col2, cI); // goes between two colors
fill(c);
beginShape();
for (let a = 0; a < 360; a += 10) {
let n1 = noise(a*noiseScale,r*noiseScale,frameCount*noiseScale);
let n2 = noise(r*noiseScale, a*noiseScale,frameCount*noiseScale);
let xOffset = sin(a) * r * n1;
let yOffset = cos(a) * r * n2;
vertex(width / 2 + xOffset, height / 2 + yOffset);
}
endShape(CLOSE);
}
filter(BLUR);
}
let basegH = 20; // base grass height
let gH = []; // all of the deviations from the base height;
let gD = 3; // grass distance
let g = []; // hold my random g green color values
let noiseScale = 0.01; // noiseScale for our grass blade animation
let windScale = 0.01;
let xOffset = []; // offset for the second x parameter so the grass blades are at a diagonal
function setup() {
createCanvas(800, 200);
strokeWeight(gD-1);
// populates our g array with random g values
for(let i = 0; i < 1000;i++){
// color
let gr = random(220,255); // generate one new value
g[i] = gr; // plug our gr random value into conseq spaces in our array
// grass height
gH[i] = basegH + random(-5,5);
xOffset[i] = random(-gD,gD);
}
}
function draw() {
background(220);
// i corresp
for(let i = 0; i<width;i+=gD){
let n = noise(i*noiseScale,frameCount*windScale); // produces results 0-1; 0.2-0.8
let nMapped = map(n,0.2,0.8,-gD,gD);
stroke(10,g[i],90);
line(i,height,i+xOffset[i]+nMapped,height-gH[i]);
}
}