The viscous moving animation with a simple morphing calculation
Simple morphing calculation and viscous moving.
It's a morphing animation made with creative coding with the 'Processing'. The lines in this animation move viscously.
The morphing method used in this code is my ordinary simple morphing calculation. it used in my other works like...
'Viscous moving' is also simple. I implemented it in this code here.
float rT = _ratioM * constrain(_ratioN + _ratioS, 0.0, 1.0);
These shapes are from the code of molding decoration of my other work 'Gates of Babylon'.
Yet another implementation example.
Using 'rect()' not 'curveVertex()' and applied 'blendMode(DIFFERENCE)'.
And also.
The 'Processing' code example.
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. To see other works based on my code is my pleasure. And my honor.
/**
* Dancing in Circles.
* A morphing animation move viscously.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2021.01.11
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
smooth();
noLoop();
}
void draw() {
int frmRate = 12;
int frmMorph = frmRate * 3; // morphing duration frames
int cycles = 6; // animation cycle no
int frmMax = frmMorph * cycles; // whole frames
// shapes
int lines = floor(random(2.0, 6.0));
int waves = floor(random(3.0, 5.0));
float radius = min(width, height) * 0.25;
float step = floor(random(1.0, 3.0)) * 0.05;
ArrayList<ArrayList<PVector>> shapes = new ArrayList<ArrayList<PVector>>();
for (int i = 0; i < cycles; i++) {
shapes.add(getShape(lines, waves, i, radius, step));
}
int nodeMax = shapes.get(0).size();
// morphing tools
ArrayList<PVector> nodesFrom = new ArrayList<PVector>();
ArrayList<PVector> nodesTo = new ArrayList<PVector>();
int cycleCnt = 0;
translate(width * 0.5, height * 0.5);
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
background(0.0, 0.0, 90.0, 100.0);
// select morphing objects
if (frmCnt % frmMorph == 0) {
cycleCnt = frmCnt / frmMorph;
nodesFrom = shapes.get(cycleCnt);
nodesTo = shapes.get((cycleCnt + 1) % cycles);
}
// easing calculation
float frmRatio = map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0);
float morphRatio = easeInOutCubic(frmRatio);
float easeRatio = InFourthPow(frmRatio);
// draw
noFill();
stroke(0.0, 0.0, 30.0, 100.0);
strokeWeight(2.0);
beginShape();
for (int i = 0; i < nodeMax + 3; i++) {
// j is for close the curve.
// ref. https://www.deconbatch.com/2021/01/processing-curvevertex-memo.html
int j = i % nodeMax;
float nodeRatio = map(j, 0, nodeMax, 0.0, 1.0);
plotVertex(nodesFrom.get(j), nodesTo.get(j), nodeRatio, easeRatio, morphRatio * morphRatio);
}
endShape();
casing();
saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* getShape : get shape points.
* @param _lines, _waves, _shape : shape parameters
* @param _radius : shape size
* @param _step : vertex points spacing
* @return : PVector array of shape points
*/
private ArrayList<PVector> getShape(int _lines, int _waves, int _shape, float _radius, float _step) {
ArrayList<PVector> line = new ArrayList<PVector>();
// curve lines
float phase = random(PI);
for (int l = 0; l < _lines; l++) {
for (float theta = 0.0; theta < TWO_PI; theta += PI * _step) {
float t = (theta + phase) % TWO_PI;
float r = _radius * (1.0 + 0.4 * sin(sin(t * (_waves + _shape) + l * TWO_PI / _lines) * TWO_PI));
float x = r * cos(t);
float y = r * sin(t);
line.add(new PVector(x, y));
}
}
return(line);
}
/**
* plotVertex : plot the vertex with morphing calculation.
* @param _from, _to : nodes to draw, morphing from and to
* @param _ratioN : vartex number ratio
* @param _ratioM : morphing ratio
* @param _ratioS : shift ratio for viscous moving
*/
void plotVertex(PVector _from, PVector _to, float _ratioN, float _ratioM, float _ratioS) {
float rT = _ratioM * constrain(_ratioN + _ratioS, 0.0, 1.0);
float rF = 1.0 - rT;
float nX = (_from.x * rF + _to.x * rT);
float nY = (_from.y * rF + _to.y * rT);
curveVertex(nX, nY);
}
/**
* easeInOutCubic easing function.
* @param t 0.0 - 1.0 : linear value.
* @return float 0.0 - 1.0 : eased value.
*/
float easeInOutCubic(float t) {
t *= 2.0;
if (t < 1.0) {
return pow(t, 3) / 2.0;
}
t -= 2.0;
return (pow(t, 3) + 2.0) / 2.0;
}
/**
* InFourthPow : easing function.
* @param _t 0.0 - 1.0 : linear value.
* @return 0.0 - 1.0 : eased value.
*/
private float InFourthPow(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}
/**
* casing : draw fancy casing
*/
private void casing() {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(54.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(50.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
noStroke();
noFill();
noStroke();
}
/*
Copyright (C) 2021- 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/>
*/
Yet another example images.