👉 この記事は日本語でも読めます。

## The original idea of this media art.

When I played with ntsutae (@ntsutae) san's work 'Symmetry 2'.

I found it creates interesting shapes if I tuned the size of rectangles.

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));

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.

## 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())'.

## The example code of the 'Processing'.

Please feel free to use this example code. 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.

``````
/**
* 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
* 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++) {
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);
}

// 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) {
}

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);
}

/*

This program is free software: you can redistribute it and/or modify