I tried to express the 'Perspective' with the digital art of simple shapes.
Digital artwork title : Working on the Building.
Digital artwork title : Night by Night.
Random walk boxes show us a nice perspective.
I tried to make some digital artwork that expresses the 'Perspective'. These skeleton boxes express it well!
This is the creative coding animation code written in Processing. It creates an animation of moving boxes.
These boxes are located by the random walking method. And move to the next location by morphing method. It's a near relation work of 'Johnny on the Monorail' about this morphing way.
Random walk panels dancing.
I made another artwork with flat panels, not boxes. It killed the perspective sensation and left us a size sensation. 🤷♀️
An example code art 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.
/**
* Working on the Building.
* Random walk boxes show us a nice perspective.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.12.05
*/
void setup() {
size(720, 480, P3D);
colorMode(HSB, 360, 100, 100, 100);
noLoop();
hint(DISABLE_DEPTH_TEST);
}
void draw() {
float boxSize = 80.0;
float walkStep = boxSize * 0.5;
float cameraDist = 300.0;
float baseHue = random(200, 230); // to make arc blue
int frmRate = 24;
int frmMorph = frmRate * 2; // morphing duration frames
int cycles = 5; // animation cycle no
int frmMax = frmMorph * cycles; // whole frames
int nodeMax = 10; // boxes number
int cycleCnt = 0;
translate(width * 0.5, height * 0.5, 0.0);
ArrayList<ArrayList<PVector>> shapes = new ArrayList<ArrayList<PVector>>();
for (int i = 0; i < cycles; i++) {
shapes.add(setNodes(nodeMax, walkStep));
}
ArrayList<PVector> nodesFrom = new ArrayList<PVector>();
ArrayList<PVector> nodesTo = new ArrayList<PVector>();
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
float frmRatio = map(frmCnt, 0, frmMax, 0.0, TWO_PI);
background(50.0, 20.0, 100.0, 100.0);
camera(
0.0, 0.0, cameraDist,
0.0, 0.0, 0.0,
0, 1, 0
);
// nodes for morphing animation. loops cyclic.
if (frmCnt % frmMorph == 0) {
cycleCnt = frmCnt / frmMorph;
nodesFrom = shapes.get(cycleCnt);
nodesTo = shapes.get((cycleCnt + 1) % cycles);
}
float toRatio = InFourthPow(map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0));
float frRatio = 1.0 - toRatio;
for (int i = 0; i < nodesTo.size(); i++) {
// morphing calculations
float nX = nodesFrom.get(i).x * frRatio + nodesTo.get(i).x * toRatio;
float nY = nodesFrom.get(i).y * frRatio + nodesTo.get(i).y * toRatio;
float nZ = nodesFrom.get(i).z * frRatio + nodesTo.get(i).z * toRatio;
drawBox(nX, nY, nZ, boxSize);
drawBox(-nX, -nY, -nZ, boxSize);
if (i == nodesTo.size() - 1) {
drawWeight(nX, nY, nZ, boxSize, baseHue, toRatio);
drawWeight(-nX, -nY, -nZ, boxSize, baseHue, toRatio);
}
}
// stop motion
if (frmCnt % frmMorph == 0) {
for (int i = 0; i < frmRate; i++) {
saveFrame("frames/" + String.format("%04d", cycleCnt) + ".00." + String.format("%04d", i) + ".png");
}
}
saveFrame("frames/" + String.format("%04d", cycleCnt) + ".01." + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* setNodes : calculate the nodes locations by random walking method.
* @param _nodeMax : node number to calculate
* @param _step : random walking step
*/
ArrayList<PVector> setNodes(int _nodeMax, float _step) {
ArrayList<PVector> node = new ArrayList<PVector>();
PVector prev = new PVector(0.0, 0.0, 0.0);
for (int i = 0; i < _nodeMax; i++) {
float rndZ = random(1.0);
if (rndZ < 0.5) {
prev.x += (floor(random(0.0, 3.0)) - 1) * _step;
prev.y += (floor(random(0.0, 3.0)) - 1) * _step;
} else if (rndZ < 0.8) {
prev.z -= _step;
} else {
prev.z += _step;
}
node.add(prev.copy());
}
return node;
}
/**
* drawBox : draw skeleton box.
* @param _x, _y, _z : location to draw
* @param _s : boz size
*/
private void drawBox(float _x, float _y, float _z, float _s) {
strokeWeight(1.0);
stroke(0.0, 0.0, 0.0, 100.0);
pushMatrix();
translate(_x, _y, _z);
noFill();
box(_s, _s, _s);
popMatrix();
}
/**
* drawWeight : draw arc and ellipse to express the weight.
* @param _x, _y, _z : location to draw
* @param _s : base size
* @param _hue : base hue value
* @param _ratio : rotation ratio
*/
private void drawWeight(float _x, float _y, float _z, float _s, float _hue, float _ratio) {
strokeWeight(1.0);
stroke(0.0, 0.0, 0.0, 100.0);
pushMatrix();
translate(_x, _y, _z);
float bHue = (_hue + 360.0 + _x * 120.0 / width);
float bSat = constrain(map(_y / height, -0.3, 0.3, 30.0, 90.0), 30.0, 90.0);
float bBri = constrain(map(_y / height, -0.3, 0.3, 100.0, 40.0), 40.0, 100.0);
float arcR = constrain(_s * map(_y / height, -0.3, 0.3, 0.8, 0.0), 0.0, _s);
float eliS = constrain(_s * map(_y / height, -0.3, 0.3, 0.0, 0.5), 0.0, _s);
fill(bHue % 360.0, bSat, bBri, 100.0);
pushMatrix();
rotateY(_ratio * PI);
arc(0.0, 0.0, arcR, arcR, PI * 1.25, PI * 1.75, PIE);
popMatrix();
fill((bHue + 180.0) % 360.0, bSat, bBri, 100.0);
ellipse(0.0, eliS * 0.5, eliS, eliS);
popMatrix();
}
/**
* 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);
}
/*
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.