Using Processing's trigonomic functions to create interesting motion in our sketches
Creative Coder working with web technologies
Adjunct Faculty @ CalArts Music Technology program
@dexterwritescode
dexterjshepherd@gmail.com
the trigonometric function that is equal to the ratio of the side opposite a given angle (in a right triangle) to the hypotenuse.
the trigonometric function that is equal to the ratio of the side adjacent to a given angle (in a right triangle) to the hypotenuse.
Red wave = sin(time)
Blue wave = cos(time)
Sine and Cosine are smoothly oscillating values between -1 and 1
ellipse(sin(frameCount * 0.1) * 100, height / 4, 10, 10);
Sine function
sin(frameCount * 0.1) * 100
Frequency ( speed of oscillation )
sin(frameCount * 0.1) * 100
Amplitute ( range of oscillation )
sin(frameCount * 0.1) * 100
Proxy for time
sin(frameCount * 0.1) * 100
frameCount
is a global variable in p5js
for(let i = 0; i < 20; i ++) {
ellipse(i * 20, sin(i) * 20, 10, 10);
}
Distance between points on the wave
( sample rate )
for(int i = 0; i < 20; i ++) {
ellipse(i * 20, sin(i) * 20, 10, 10);
}
Proxy for time
for(int i = 0; i < 20; i ++) {
ellipse(i * 20, sin(i) * 20, 10, 10);
}
Amplitude
for(int i = 0; i < 20; i ++) {
ellipse(i * 20, sin(i) * 20, 10, 10);
}
Animation
for(let i = 0; i < 20; i ++) {
ellipse(i * 20, sin(i + frameCount * 0.1) * 20, 10, 10);
}
Use frameCount or some other changing variable ( another sine or cosine function?!?! ) to animate the wave phase over time.
If your frequency is to high, multiply by some small constant
// rotate() will rotate the canvas clockwise
rotate(???)
for(let i = 0; i < 5; i ++ ) {
rect(i * 10, height / 2, 10, 10);
}
What input to the rotate function will change the left image to the right image?
rotate(PI/4)
for(let i = 0; i < 5; i ++ ) {
rect(i * 10, height / 2, 10, 10);
}
A circle has 360 degrees
A circle has Pi * 2 ( Tau ) radians
All processing functions dealing with angles will expect radians
You can convert between degrees and radians with the
degrees()
and radians()
functions
or change the expected arguments globally with the angleMode()
function.
But you probably won't want to.
const radius = 100;
const numPoints = 20;
for(let i = 0; i < numPoints; i ++) {
let angle = map(i, 0, numPoints, 0, TWO_PI);
let x = sin(angle) * radius;
let y = cos(angle) * radius;
ellipse(x, y, 5, 5);
}
const radius = 100;
const numPoints = 10;
for(let i = 0; i < numPoints; i ++) {
let angle = map(i, 0, numPoints, 0, TWO_PI);
let x = sin(angle) * radius;
let y = cos(angle) * radius;
ellipse(x, y, 5, 5);
}
use the map function to convert the range 0 - numPoints to 0 - Tau
const radius = 100;
const numPoints = 10;
for(let i = 0; i < numPoints; i ++) {
let angle = map(i, 0, numPoints, 0, TWO_PI);
let x = sin(angle) * radius;
let y = cos(angle) * radius;
ellipse(x, y, 5, 5);
}
sin
and cos
will return values between
-1 and 1 so multiply by radius and use as x and y coords for the circle.
const amplitude = 50;
const numPoints = 20;
for(let i = 0; i < numPoints; i ++) {
let angle = map(i, 0, numPoints, 0, TWO_PI);
let pos = sin(angle) * amplitude;
ellipse(i * 10, pos, 5, 5);
}
let angle = map(mouseX, 0, width, 0, TWO_PI);
rotate(angle);
let angle = map(mouseX, 0, width, 0, TWO_PI);
rotate(angle);
Use the map function to change any arbitrary stream of values into a useable angle.
Last steps ...
rotate()
actually do?
rotate(frameCount * 0.1);
rect(width / 2, height / 2, 100, 100);
Instead of spinning rectangle, we see the rectangle spin off screen and reappear on the other side some time later?
The rotate function rotates the canvas around the point of origin, in our case, (0, 0) - the top left corner of the screen.
in order to rotate the rectange around its center point, we need to change the origin point. To do this we need ...
translate(width / 2, height / 2);
rotate(frameCount * 0.1);
rect(0, 0, 100, 100);
translate(width / 2, height / 2);
rotate(frameCount * 0.1);
rect(0, 0, 100, 100);
we use the translate
function to change the origin from (0, 0) to
( width / 2, height /2 ).
translate(width / 2, height / 2);
rotate(frameCount * 0.1);
rect(0, 0, 100, 100);
By rotating after the translation we rotate around the new origin instead of (0, 0).
translate(width / 2, height / 2);
rotate(frameCount * 0.1);
rect(0, 0, 100, 100);
Becuase we translated the origin to ( width / 2, height / 2 ) we can draw the rect at ( 0, 0 ) - the new origin.
translate(width * 0.25, height * 0.25);
rect(0, 0, 20, 20 );
translate(width * 0.25, height * 0.25);
rect(0, 0, 20, 20 );
translate(width * 0.25, height * 0.25);
rect(0, 0, 20, 20 );
We can stack rotations and translations together by calling the functions multiple times.
All translation and rotations are reset at the end of the draw
loop
translate(width * 0.5, 0);
for(let i = 0; i < 20; i ++) {
let angle = map(i, 0, 20, 0, TWO_PI);
for(let j = 0; j < 10; j++ ) {
translate(10, 15);
rotate(angle / 10);
rect(0, 0, j + 2 * 0.5, j + 2 * 0.5);
}
}
Using for
and while
loops, we can create complex patterns by repeating
translate and rotate manipulations
rectMode(CENTER);
translate(width * 0.25, 0);
for(int i = 0; i < 10; i++) {
pushMatrix();
float x = map(i, 0, 10, 0, width * 0.5);
translate(x, height * 0.5);
if ( i % 2 == 0 ) {
rotate(frameCount * 0.01);
} else {
rotate(frameCount * -0.01);
}
rect(0, 0, 50, 50);
popMatrix();
}
so we use pushMatrix()
and popMatrix()
to reset the translation and rotation matrices