How I made this creative coding animation of a strange kind of node garden.
It's an animation of a strange kind of Node Garden.
It's a creative coding animation made with the 'Processing' programming language. It produces an animation of the simple node garden image morphing to another node garden.
The ordinary Node Garden you see a lot.
You may have seen creative coding using the node garden technique like this. Randomly located nodes, and lines that are determined with distance.
if (dist(xa, ya, xb, yb) < 100) {
line(xa, ya, xb, yb);
}
It's not bad. But it tends to be a too complex and confusing look.
Make it simple.
It looks simple if you locate nodes on the grid.
pvs.push(createVector(
floor(random(1.0, 10.0)) / 10,
floor(random(1.0, 10.0)) / 10
));
And more, you can draw lines not by these distance but by x-y axis.
if (xa == xb || ya == yb) {
line(xa, ya, xb, yb);
}
Follow your interest.
It creates interesting results. I added code to change the node size by the line count.
Then, let it move!
// morphing
float xF = _to.get(f).x * _rate + _from.get(f).x * (1.0 - _rate);
float yF = _to.get(f).y * _rate + _from.get(f).y * (1.0 - _rate);
That's it! This is the fun of creative coding!
An example code of the 'Processing'.
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. 😀
/**
* Johnny on the Monorail.
* It's an animation of a strange kind of Node Garden.
*
* @author @deconbatch
* @version 0.1
* Processing 3.5.3
* 2020.08.25
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
smooth();
noLoop();
}
void draw() {
int nodeCnt = 30;
int frmMax = 24 * 12; // 24fps x 12sec
int frmMorph = 24 * 4; // morphing duration frames
ArrayList<PVector> nodesFrom = new ArrayList<PVector>();
ArrayList<PVector> nodesTo = setNodes(nodeCnt);
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
float easeRatio = InFourthPow(map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0));
// copy to -> from
if (frmCnt % frmMorph == 0) {
nodesFrom = new ArrayList<PVector>(nodesTo);
nodesTo = setNodes(nodeCnt);
}
blendMode(BLEND);
background(0.0, 0.0, 90.0, 100.0);
fill(0.0, 0.0, 90.0, 100.0);
stroke(0.0, 0.0, 10.0, 100.0);
strokeWeight(2.0);
construct(nodesFrom, nodesTo, easeRatio);
blendMode(BLEND);
casing();
saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* setNodes : set nodes to draw.
* @param _cnt any : node count.
* @return : nodes in ArrayList<PVector>.
*/
private ArrayList<PVector> setNodes(int _cnt) {
ArrayList<PVector> n = new ArrayList<PVector>();
for (int i = 0; i < _cnt; i++) {
n.add(new PVector(
floor(random(2.0, 9.0)) / 10.0,
floor(random(2.0, 9.0)) / 10.0
));
}
return n;
}
/**
* construct : calculate morphing location and draw.
* @param _from : nodes of start location of morphing.
* @param _to : nodes of end location of morphing.
* @param _rate 0.0 - 1.0 : start(0.0) - end(1.0)
*/
private void construct(ArrayList<PVector> _from, ArrayList<PVector> _to, float _rate) {
for (int f = 0; f < _from.size() - 1; f++) {
int cons = 0;
float xF = _to.get(f).x * _rate + _from.get(f).x * (1.0 - _rate);
float yF = _to.get(f).y * _rate + _from.get(f).y * (1.0 - _rate);
for (int t = f + 1; t < _to.size(); t++) {
float xT = _to.get(t).x * _rate + _from.get(t).x * (1.0 - _rate);
float yT = _to.get(t).y * _rate + _from.get(t).y * (1.0 - _rate);
if (abs(xF - xT) < 0.01 || abs(yF - yT) < 0.01) {
line(xF * width, yF * height, xT * width, yT * height);
cons++;
}
}
if (cons % 2 == 0) {
rect(xF * width, yF * height, cons * 5.0, cons * 5.0, 4);
} else {
ellipse(xF * width, yF * height, cons * 5.0, cons * 5.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
*/
public void casing() {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(30.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
strokeWeight(28.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
}
/*
Copyright (C) 2020- 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.