An animation Media art of the generative design of rectangles
The original idea of this media art.
When I played with ntsutae (@ntsutae) san's work 'Symmetry 2'.
//#つぶやきProcessing
— ntsutae (@ntsutae) March 6, 2021
t=0
draw=_=>{createCanvas(w=640,w)
noStroke();fill(0)
t+=.005;x=y=w/2
for(i=2e3;i--;){
d=8*sin(9*(i/200+t|i/10+t))
d=PI/2*int(d)
rect(x+=cos(d),y+=sin(d),3,3)
rect(w-x,y,3,3)
}}//https://t.co/hJ6JA1wkD5 pic.twitter.com/eNJn0U2xTn
I found it creates interesting shapes if I tuned the size of rectangles.
どこに行き着くのかわからない階段😰#p5js #creativecoding #OpenSourcehttps://t.co/w1hMxgMoCM pic.twitter.com/uWLut8qbrT
— deconbatch (@deconbatch) March 9, 2021
And I tried to make it interesting media art, I used 'blendMode(DIFFERENCE)' and tuned the edge size of the rectangle.
Making my own work.
The original ntsutae san's work used logical operation to determine the shape. But it does not necessarily need the logical operation to make a shape randomly. So I changed the formula of shape calculation to the formula I can easily understand.
float theta = HALF_PI * floor(8 * sin(shapeBase + shapeDiv * i));
ひとまずランダムに生成したものをスライドショーにして様子を見る。👓#processing #creativecoding pic.twitter.com/3yp58NhvJK
— deconbatch (@deconbatch) May 17, 2021
I proceeded to tune the size and the width of the edge of rectangles and made the whole shape locate to the center of the canvas.
キャンバスの端に寄ったりはみ出したりなので、なるべく中央に寄せて描画するよう調整。👉👈#processing #creativecoding pic.twitter.com/lOT9r4UY1j
— deconbatch (@deconbatch) May 19, 2021
Make it move with simple morphing technique.
I called it 'Simple morphing technique', but it is just a linear interpolation.
I used to calculate the interpolation by myself like 'Johnny on the Monorail'.
float xF = _to.get(f).x * _rate + _from.get(f).x * (1.0 - _rate);
And I found the 'lerp()' function at last! Ahh! what a divine blessing!
float x = lerp(shapeFrom.get(i).x, shapeTo.get(i).x, easeRatio);
Finally, I made this media art as a loop animation.
During the way, I made some failed creative work. It's a 'strokeWeight(random())'.
スライドショーじゃ味気ないので徐々に形が変化するアニメーションにするつもりが、思ってたのと違う〜! 🤣#processing #creativecoding pic.twitter.com/YHepA7z6CG
— deconbatch (@deconbatch) May 19, 2021
The example code of the 'Processing'.
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.
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.
/**
* Good Times Bad Times.
* It's a media art that displays the morphing generative design of rectangles.
* original idea : https://openprocessing.org/sketch/1125777
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2021.05.23
*/
void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
rectMode(CENTER);
smooth();
}
void draw() {
int frmRate = 30;
int frmMorph = frmRate * 1; // morphing duration frames
int cycles = 8; // animation cycle no
int frmMax = frmMorph * cycles; // whole frames
float rSize = 25.0;
// generate shapes
ArrayList<ArrayList<PVector>> shapes = new ArrayList<ArrayList<PVector>>();
float weights[] = new float[cycles];
for (int i = 0; i < cycles; i++) {
shapes.add(getShape(rSize * 2.0));
weights[i] = rSize * floor(random(6));
}
// variables for animation
ArrayList<PVector> shapeFrom = new ArrayList<PVector>();
ArrayList<PVector> shapeTo = new ArrayList<PVector>();
float weightFrom = 0.0;
float weightTo = 0.0;
int cycleCnt = 0;
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
float frmRatio = map(frmCnt, 0, frmMax, 0.0, 1.0);
float easeRatio = InFourthPow(map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0));
// shape for morphing animation. loops cyclic.
if (frmCnt % frmMorph == 0) {
cycleCnt = frmCnt / frmMorph;
shapeFrom = shapes.get(cycleCnt);
shapeTo = shapes.get((cycleCnt + 1) % cycles);
weightFrom = weights[cycleCnt];
weightTo = weights[(cycleCnt + 1) % cycles];
}
// draw
blendMode(BLEND);
background(0.0, 0.0, 100.0, 100.0);
blendMode(DIFFERENCE);
fill(0.0, 0.0, 100.0, 100.0);
stroke(0.0, 0.0, 100.0, 100.0);
strokeWeight(lerp(weightFrom, weightTo, easeRatio));
for (int i = 0; i < shapeFrom.size(); i++) {
float x = lerp(shapeFrom.get(i).x, shapeTo.get(i).x, easeRatio);
float y = lerp(shapeFrom.get(i).y, shapeTo.get(i).y, easeRatio);
rect(x, y, rSize, rSize);
}
blendMode(BLEND);
casing();
// for 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");
}
}
// for moving motion
saveFrame("frames/" + String.format("%04d", cycleCnt) + ".01." + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* getShape : generates the shape
*/
ArrayList<PVector> getShape(float _size) {
int pvNum = 15;
float shapeBase = random(TWO_PI);
float shapeDiv = random(HALF_PI);
float x = 0.0;
float y = 0.0;
ArrayList<PVector> pvs = new ArrayList<PVector>();
for (int i = 0; i < pvNum; i++) {
float theta = HALF_PI * floor(8 * sin(shapeBase + shapeDiv * i));
x += _size * cos(theta);
y += _size * sin(theta);
pvs.add(new PVector(x, y));
}
// centering the shape
float xMin = width;
float xMax = 0;
float yMin = height;
float yMax = 0;
for (PVector pv : pvs) {
xMin = min(xMin, pv.x);
xMax = max(xMax, pv.x);
yMin = min(yMin, pv.y);
yMax = max(yMax, pv.y);
}
float xDiv = (width - xMin - xMax) * 0.5;
float yDiv = (height - yMin - yMax) * 0.5;
for (PVector pv : pvs) {
pv.add(xDiv, yDiv);
}
return pvs;
}
/**
* InFourthPow : easing function.
*/
private float InFourthPow(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}
/**
* casing : draws fancy casing
*/
void casing() {
float w = min(width, height) * 0.05;
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(w + 4.0);
stroke(0.0, 0.0, 0.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
strokeWeight(w);
stroke(0.0, 0.0, 100.0, 100.0);
rect(width * 0.5, height * 0.5, width, height);
}
/*
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/>
*/