Make a 'Stepwise easing' with the various easing functions
The effect of the change in speed called 'Easing' makes your animation more attractive.
イージング有り/なしの動き 🙂
— deconbatch (@deconbatch) January 22, 2022
上がなしで、下が easeInCubic のイージング。#p5js #creativecoding pic.twitter.com/xGbyDXYp5i
The upper one has no easing effect. The under one got an easing effect.
Let me show you the 'Stepwise easing' made with various easing functions. And the example code of animation using the 'Stepwise easing'.
The various easing functions.
What is the 'easing'?
'Easing' is generally the effect of the change in speed. In the programming code, it'll be the function that changes the parameter value from 0.0 to 1.0 with some curve.
For example, the code and the graph of the animation shown before are like these.
// no easing
function noEasing(x) {
return x;
}
// easing
function easing(x) {
return x * x * x;
}
The left one has no easing effect. The right one got an easing effect. The x-axis is the parameter value of the function. And the y-axis is the return value of the function. The graph of the easing function is just a graph of x cubed.
How can I make an easing function?
There are various easing functions, and you can see these in the 'Easing Cheat Sheet'.
'Easing Cheat Sheet' from the Robert Penner's Easing Functions
https://easings.net/
You can see the description of the function when you click each graph. And there is a code in the section of 'Math function'. The code is written in TypeScript, and you can use it in 'p5.js' with some change.
// TypeScript
function easeInCubic(x: number): number {
return x * x * x;
}
// p5.js
function easeInCubic(x) {
return x * x * x;
}
The example 'p5.js' code using the 'easeInCubic' easing.
easeInCubic の作例 😀
— deconbatch (@deconbatch) January 22, 2022
function easeInCubic(x) {
return x * x * x;
}#p5js #creativecoding pic.twitter.com/XaKBZG7N3n
// Rotating circles.
const w = 720;
const h = w;
const cNum = 3;
const fRate = 30;
const cycle = fRate * 2;
function setup() {
createCanvas(w, h);
frameRate(fRate);
}
function draw() {
const ease = easeInCubic((frameCount % cycle) / cycle)
translate(w * 0.5, h * 0.5);
background(240);
noStroke();
for (let c = 0; c < cNum; c++) {
let r = 0.2 * (0.5 + sin(PI * ease));
let t = TWO_PI * (ease + c / cNum);
let x = w * r * cos(t);
let y = h * r * sin(t);
fill((c * 100) % 255);
circle(x, y, w * 0.1);
}
}
// easing function
function easeInCubic(x) {
return x * x * x;
}
Using many functions at once.
I thought that chaining many easing functions might be some new easing movement. So I drew this graph.
This graph used five functions. And the result looks like a stairway so I call it 'Stepwise easing'.
These are example animations. Using one 'easeInOutCubic' function.
easeInOutCubic イージングの繰り返し 😌#p5js #creativecoding pic.twitter.com/eBQkm1XQOX
— deconbatch (@deconbatch) January 22, 2022
Chaining three functions 'easeInOutCubic', 'easeOutQuad', 'easeInCubic'.
easeInOutCubic, easeOutQuad, easeInCubic の一連のイージングで一回転のパターン。🙂#p5js #creativecoding pic.twitter.com/d54IRZIycX
— deconbatch (@deconbatch) January 22, 2022
Using the 'Stepwise easing' makes various movements than using only one easing function. You may enjoy the new movement every time if you change the sequence of functions randomly.
The example code of 'Processing' using the 'Stepwise easing'.
I was interested in the rectangles drawn with the 'blendMode(DIFFERENCE)'.
The pattern in the middle of the movement that is characteristic with the 'blendMode(DIFFERENCE)' looked good. So I wanted to show the stop motion, and it is suitable for the 'Stepwise easing'.
This code does not display any images on the screen but generates image files in frames directory. You can make an animation with these files.
Please feel free to use this example code under the terms of the GPL.
/**
* Life Goes Round.
* an animation using step easing.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2022.01.23
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
smooth();
noLoop();
rectMode(CENTER);
int frmRate = 30;
int cycleSec = 3;
int frmMax = frmRate * cycleSec;
float rectSiz = min(width, height) * random(0.5, 0.8);
float phaseR = random(PI);
float phaseT = random(PI);
float hueOrg = random(360.0);
// easing functions
ArrayList<Ease> easing = new ArrayList<Ease>();
easing.add(new InOutQuart());
easing.add(new OutQuart());
easing.add(new InBack());
easing.add(new InQuad());
easing.add(new OutBack());
int cycleMax = easing.size();
int easingStart = floor(random(cycleMax));
translate(width * 0.5, height * 0.5);
noStroke();
float easePrev = 0.0;
float easeRatio = 0.0;
for (int cycleCnt = 0; cycleCnt < cycleMax; cycleCnt++) {
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
// step easing
float frmRatio = map(frmCnt, 0, frmMax - 1, 0.0, 1.0);
easeRatio = easePrev + easing.get((easingStart + cycleCnt) % cycleMax).ease(frmRatio) / cycleMax;
float radii = abs(sin(phaseR + easeRatio * PI)) * rectSiz * 0.3;
float hueBase = hueOrg + 360.0 * easeRatio;
blendMode(BLEND);
background(hueBase % 360.0, 30.0, 60.0, 100.0);
blendMode(DIFFERENCE);
fill((hueBase + 60.0) % 360.0, 30.0, 80.0, 100.0);
for (int p = 0; p < 8; p++) {
int sign = (p % 2 == 0) ? 1 : -1;
for (float r = 0.2; r < 0.5; r += 0.1) {
float t = PI * 0.25 * p + sign * (phaseT + TWO_PI * easeRatio) * r * 2.5;
float x = r * width * cos(t);
float y = r * height * sin(t);
rect(x, y, rectSiz, rectSiz, radii);
}
}
saveFrame("frames/" + String.format("%02d", cycleCnt) + ".00." + String.format("%04d", frmCnt) + ".png");
}
// for stop motion
for (int i = 0; i < frmRate; i++) {
saveFrame("frames/" + String.format("%02d", cycleCnt) + ".01." + String.format("%04d", i) + ".png");
}
easePrev = easeRatio;
}
exit();
}
/**
* Ease : hold easing functions.
* reference : Robert Penner's Easing Functions (https://easings.net/)
*/
public interface Ease {
public float ease(float _t);
}
public class InOutQuart implements Ease {
public float ease(float _t) {
return (_t < 0.5) ? 8.0 * _t * _t * _t * _t : 1 - pow(-2.0 * _t + 2.0, 4) / 2.0;
}
}
public class OutQuart implements Ease {
public float ease(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}
}
public class InQuad implements Ease {
public float ease(float _t) {
return pow(_t, 2);
}
}
public class InBack implements Ease {
public float ease(float _t) {
float c1 = 1.70158;
float c3 = c1 + 1;
return c3 * _t * _t * _t - c1 * _t * _t;
}
}
public class OutBack implements Ease {
public float ease(float _t) {
float c1 = 1.70158;
float c3 = c1 + 1;
return 1.0 + c3 * pow(_t - 1.0, 3) + c1 * pow(_t - 1.0, 2);
}
}
/*
Copyright (C) 2022- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/