Week 7 — Harmonic Motion and Animation

Harmonic Motion with noise

Random on Separate Refresh

More control over using the random and noise functions

Example link: random with modulos and noise

The same example is also in the 7.1 code folder.

Repetition & Oscillation and Linear Motion

In this section, there is discussion on two types of animation.

  1. Repetition - Animation that repeats from the beginning
    • Repetition uses modulus to start from beginning
  2. Oscillation - Animation that swings back and forth like a pendulum
    • Uses sine and cosine functions to oscillate between -1 and 1.

Examples - Repetitive motion

var x = 0;

function setup(){
    createCanvas(400, 400);
    noStroke();
}

function draw(){
    background(220);
    translate(0, height/4);
    fill(255, 0, 0);
    rect(x, 0, 100, 100);
    x++;
    // Using modulo is much better than using a conditional here.
    x = x % width;
}
  • Other words to describe oscillating motion are periodic motion or harmonic motion.

Examples - oscillating motion

let yPos;
var ySpeed = 1;
var radius = 50;

function setup() {
    createCanvas(400, 400);
    yPos = height / 2;
}

function draw() {
    background(220);
    yPos = yPos + ySpeed;
    if (yPos + radius / 2 > height || yPos - radius / 2 < 0) {
        ySpeed *= -1.0;
    }
    ellipse(width / 2, yPos, radius);
}

Sine and Cosine

Sine and cosine (waves) functions.

sine & cosine function

Amplitude: The maximum and minimum extents of oscillation. By default, sin() and cos() produce outputs in range -1 to 1.

Period (wavelength): The time taken to complete 1 oscillation. i.e., for the angle to increase from 0 to TWO_PI (radians).

Demo of sin(). Check the output of below code to see how a sine function behaves. Observe how the output value oscillates between -1 and 1.

function setup(){
    createCanvas(400, 400);
    //limits frame rate
    frameRate(10);
}

function draw(){
    background(255);
    var val = sin(radians(frameCount));
    console.log(val);
}

Observe that sine and cosine are offset (out of phase) by a value of PI/2.

Example: Elastic Motion

var radius = 50;

function setup() {
    createCanvas(400, 400);
}

function draw() {
    background(220);
    var amplitude = height / 2 - radius / 2;
    // - radius/2 for cosmetics: To account for radius during bounce
    var y = sin(radians(frameCount)) * amplitude;
    translate(width / 2, height / 2);
    ellipse(0, y, radius);
}

This is similar to example in section 7.2 Linear motion. But there are no conditional statements to check or change the direction of motion.

Inspiration for Motion Graphics

Examples

  1. mr. div
  2. 89-A
  3. dvdp
  4. The harmonic series

Example code make the object go in a circle

var radius = 25;
var xSpeed = 4.0;
var angle = 0.0;

function setup() {
    createCanvas(400, 400);
}

function draw() {
    background(220);
    translate(width / 2, height / 2);
    var amplitude = height / 2 - radius / 2;
    angle += 2.0;
    var x = cos(radians(angle)) * amplitude;
    var y = sin(radians(angle)) * amplitude;
    fill(100);
    ellipse(x, y, radius);
    x += xSpeed;
}

Lissajous Curves

A Lissajous curve, also known as Lissajous figure or Bowditch curve, is the graph of a system of parametric equations x=A/sin; y=B/sin, which describe complex harmonic motion.

Wikipedia: Lissajous Curves

Render using the code in folder /7.4

Lissajous

Example sketches

The p5 sketches for this week, from the course repo.

7.1 — Harmonic Motionrepo ↗
/**
 * Using modulo, random, and noise (perlin noise) to generate random unwinding shapes
 * References:  http://p5js.org/reference/#/p5/noise
 * Aesthetic inspired by: John Whitney (https://www.youtube.com/watch?v=TbV7loKp69s)
 **/
var shapeWidth;
var shapeHeight;
var vertCount;
var framesTilRefresh = 60;

function setup() {
  createCanvas(windowWidth, windowHeight);
  shapeWidth = random(width / 2);
  shapeHeight = random(height / 2);
  vertCount = 10;
}

function draw() {
  background(100);
  translate(width / 2, height / 2);
  //using the modulo operator we can recalculate our vertCount every framesTilRefresh frames
  if (frameCount % framesTilRefresh === 0) {
    vertCount = floor(noise(frameCount) * 100);
  }
  if (frameCount % (framesTilRefresh * 6) === 0) {
    shapeWidth = random(width / 2);
    shapeHeight = random(height / 2);
  }
  makeShape(shapeWidth, shapeHeight, vertCount);
  if (vertCount > 0 && frameCount % 4 === 0) {
    vertCount--;
  }
}

function makeShape(_width, _height, verts) {
  noFill();
  beginShape(LINE_STRIP);
  for (var i = 0; i < verts; i++) {
    var x = cos((i * verts) / TWO_PI) * _width;
    var y = sin((i * verts) / TWO_PI) * _height;
    curveVertex(x, y);
  }
  endShape();
}
7.2 — Linear Motionrepo ↗
let yPos;
var ySpeed = 1;
var radius = 50;

function setup() {
  createCanvas(400, 400);
  yPos = height / 2;
}

function draw() {
  background(220);
  yPos = yPos + ySpeed;
  if (yPos + radius / 2 > height || yPos - radius / 2 < 0) {
    ySpeed *= -1.0;
  }
  ellipse(width / 2, yPos, radius);
}
7.3 — Elastic Motionrepo ↗
var radius = 25;
var xSpeed = 4.0;
var angle = 0.0;

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
  translate(width / 2, height / 2);
  var amplitude = height / 2 - radius / 2;
  angle += 2.0;
  var x = cos(radians(angle)) * amplitude;
  var y = sin(radians(angle)) * amplitude;
  fill(100);
  ellipse(x, y, radius);
  x += xSpeed;
}
7.4 — Lissajous Curvesrepo ↗
var periodOne = 125.0;
var periodTwo = 90.0;
var pointCount = 0;
var angle = 0;
var amplitude = 300;

function setup() {
  createCanvas(600, 600);
  background(220);
}

function draw() {
  noFill();
  strokeWeight(1);
  stroke(100);
  translate(width / 2, height / 2);
  if (pointCount > 2250) {
    noLoop();
  }
  beginShape();
  for (var i = 0; i < pointCount; i++) {
    angle = (i / periodOne) * TWO_PI;
    var x = sin(angle) * amplitude;
    angle = (i / periodTwo) * TWO_PI;
    var y = sin(angle) * amplitude;
    vertex(x, y);
  }
  endShape();
  pointCount++;
}