![見出し画像](https://assets.st-note.com/production/uploads/images/109978891/rectangle_large_type_2_996d0199ad613c1fce948c71b9fa7b9c.png?width=1200)
p5.js ジェネラティブアートのメイキング 「OVERLAY」編
ところどころにじみっぽいアニメーションできた〜!
— レオナ (@reona396) June 20, 2023
OpenProcessinghttps://t.co/pBVLernCub
NEORThttps://t.co/RSBXR3KGOZ#p5js #creativecoding #generative pic.twitter.com/DY5JSLDGSu
こちらの作品のメイキングを書いてみました!
(実際に投稿したコードからメイキング用に整理したのでちょこちょこ違うところありますがお気になさらず…)
インスピレーションにつながれば嬉しいです!
1. テンプレートの読み込み
p5.jsで作品をつくる時のために自分用のテンプレートを用意しており、毎回コピーして利用しています。
なんらかの動きと見た目のクラスです。
// テンプレート
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
background("#E7ECF2");
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {}
move() {}
display() {}
}
2. ランダムな位置に円を描く
テンプレートを修正して、10個の円をランダムな位置に描くようにします。
// ランダムな位置に10個の円を描く
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
background("#E7ECF2");
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = random(width);
this.y = random(height);
this.d = random(10, 50)
}
move() {}
display() {
// 円の位置や大きさをランダムにしつつ描画
circle(this.x, this.y, this.d);
}
}
![](https://assets.st-note.com/img/1687619925529-MGkoJkvdHO.png?width=1200)
3. 円に動きをつけて軌跡を描画する
円に動きをつけます。
なめらかな乱数を出力するnoiseを活用して、円をなめらかにランダムに動かすようにします。
また、背景色の更新をせず、軌跡を描画するようにします。
うにょうにょとした動きが描画されました!
// 円に動きをつけて軌跡を描く
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
// background("#E7ECF2");
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(10, 50);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
}
move() {
// 円の動きにnoiseを導入
this.x = width * noise(this.n, this.nx);
this.y = height * noise(this.n, this.ny);
this.n += 0.005;
}
display() {
circle(this.x, this.y, this.d);
}
}
![](https://assets.st-note.com/img/1687620938336-fehuJww10Y.png?width=1200)
4. 円の動きをダイナミックにする
上記のコードのようなnoiseの使用方法だと、円の動きが画面中央にかたよるので移動範囲を広げてダイナミックにします。
(この辺、他のクリエイティブコーダーさんはどうやってるんだろう…noiseを利用しつつダイナミックに動かす方法をご存知の方はぜひ教えてください!)
// noiseの範囲を調整して動きをより大きく
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(10, 50);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
}
move() {
// noiseの範囲を大きくして動きをダイナミックに
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
circle(this.x, this.y, this.d);
}
}
![](https://assets.st-note.com/img/1687960509257-Pjx2u91QhA.png?width=1200)
5. 図形を六角形に変更する
うにょうにょ動く図形を六角形に変更します。
理由は「今年はストリートファイターも6だしアマコアも6だしFFは16だし6に縁があるなぁ」と思ったからです。
// 図形を六角形に変更
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(10, 50);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
push();
translate(this.x, this.y);
// 円から六角形に書き換え
beginShape();
for (let i = 0; i < 360; i += 360 / 6) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1687962045520-mpSCwV0uAI.png?width=1200)
6. 図形を回転させる
このままだと動きが単調なので、六角形をそれぞれ回転させます。
角のある図形は回転させると独特の味わいのある軌跡を描くので面白いです。
回転スピードや回転方向はランダムに設定します。
// 六角形を回転させる
let shapes = [];
const shapesNum = 10;
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(10, 50);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
push();
translate(this.x, this.y);
// 六角形を回転させる。スピードや回転方向は個体ごとにランダム
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += 360 / 6) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1687962372823-AIkKo4jEgh.png?width=1200)
7. 図形に色をつける
図形のかたちや動きが固まってきたので色をつけていきます。
カラーパレットを用意して、その中から図形それぞれにランダムにピックするように設定します。
// 図形に色をつける
let shapes = [];
const shapesNum = 10;
// カラーパレットを配列で定義
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(10, 50);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = random(palette);
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
// 図形に塗りつぶしの色をつける
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += 360 / 6) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1687963682640-ICwtiFAtPs.png?width=1200)
8. 背景色をつける&図形の色やサイズを調整する
背景色の設定をパレットの一番先頭の色にしてみます。
また、図形の色に思いきって透明度を設定してみます。ちょっと水彩画風です。
図形のサイズも大きいのから小さいのまで出現するようにします。
// 背景色を設定して図形の透明度と大きさを整える
let shapes = [];
const shapesNum = 10;
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
noStroke();
// 背景色を設定
background(palette[0]);
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
// 図形のサイズにバラつきを持たせる
this.d = random(5, 100);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = color(random(palette));
// 図形の透明度を設定
this.c.setAlpha(random(5, 30));
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += 360 / 6) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1688047256570-BPOTuhzCug.png?width=1200)
9. 図形のバリエーションを増やす
透明度を設定した状態で六角形を転がすと、円っぽく見えることに気がつきました。
これだと角のある図形を転がす意味が薄くなるので、六角形に加えて三角形も図形のバリエーションとして増やしてみることにします。
// 図形のバリエーションを六角形と三角形に変更
let shapes = [];
const shapesNum = 10;
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
noStroke();
background(palette[0]);
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(5, 100);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = color(random(palette));
this.c.setAlpha(random(5, 30));
// 図形の頂点の数を3と6でランダムにすることで三角形と六角形をランダムに描画
this.shapeAngle = 360 / random([3, 6]);
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += this.shapeAngle) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1688048654417-Hy859h3owa.png?width=1200)
10. 図形の数を増やす
今までは図形の数は仮で10個でした。
図形の動きや形や色がいい感じになってきたので、100個に増やしてみます!
// 100個に図形を増やす
let shapes = [];
// 図形の数を増やす
const shapesNum = 100;
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
noStroke();
background(palette[0]);
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.d = random(5, 100);
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = color(random(palette));
this.c.setAlpha(random(5, 30));
this.shapeAngle = 360 / random([3, 6]);
}
move() {
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += this.shapeAngle) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1688048742323-fn6KjPQCrm.png?width=1200)
11. 図形のサイズを周期的に変化させる
画面に活発な動きがもっと欲しいと思ったので、図形のサイズを周期的に大きくしたり小さくしたりさせてみます。
// 図形の大きさを周期的に変化させる
let shapes = [];
const shapesNum = 100;
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
noStroke();
background(palette[0]);
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
// 図形のサイズの最大値をランダムに設定
this.maxD = random(5, 100);
this.d = 0;
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = color(random(palette));
this.c.setAlpha(random(5, 30));
this.shapeAngle = 360 / random([3, 6]);
}
move() {
// 図形のサイズをゼロから設定された最大値までの間で周期的に変化させる
this.d = this.maxD * abs(sin(this.n * 1000));
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += this.shapeAngle) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1688475466066-sXnSalOIJd.png?width=1200)
12. 図形の一部にオーバーレイをかける
全体的にのっぺりしてしまったので、blendModeをかけようと思いました。
色々試した結果、オーバーレイをかけるのがよさそうです!
すべての図形ではなく、一部にしぼってオーバーレイをかけてみます。
// 図形の一部をオーバレイで描画
let shapes = [];
const shapesNum = 100;
const palette = ["#0276D1", "#011E60", "#79BCC9", "#F6F5BE", "#269182"];
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(DEGREES);
for (let i = 0; i < shapesNum; i++) {
shapes.push(new Shape());
}
noStroke();
background(palette[0]);
}
function draw() {
for (let i = 0; i < shapes.length; i++) {
// 図形の一部にオーバーレイをかける。それ以外は通常描画
if (i < shapes.length / 3) {
blendMode(BLEND);
} else {
blendMode(OVERLAY);
}
shapes[i].move();
shapes[i].display();
}
}
class Shape {
constructor() {
this.x = 0;
this.y = 0;
this.maxD = random(5, 100);
this.d = 0;
this.nx = random(1000);
this.ny = random(1000);
this.n = random(1000);
this.rotateSpeed = random(3, 10) * random([-1, 1]);
this.c = color(random(palette));
this.c.setAlpha(random(5, 30));
this.shapeAngle = 360 / random([3, 6]);
}
move() {
this.d = this.maxD * abs(sin(this.n * 1000));
this.x = map(noise(this.n, this.nx), 0, 1, -width * 0.5, width * 1.5);
this.y = map(noise(this.n, this.ny), 0, 1, -height * 0.5, height * 1.5);
this.n += 0.005;
}
display() {
fill(this.c);
push();
translate(this.x, this.y);
rotate(frameCount * this.rotateSpeed);
beginShape();
for (let i = 0; i < 360; i += this.shapeAngle) {
vertex(cos(i) * this.d, sin(i) * this.d);
}
endShape(CLOSE);
pop();
}
}
![](https://assets.st-note.com/img/1688481032632-hRCFPJ1WXi.png?width=1200)
というわけで…完成!
オーバーレイによってところどころにじみのような効果になっているのがお気に入りです!!
![](https://assets.st-note.com/img/1688482238631-0lkwQOYnEH.png?width=1200)
というわけで、「OVERLAY」のメイキングでした!
OpenProcessingとNEORTにアニメーションとして動作するコードを投稿してあるのでこちらもぜひ見てくださいね〜!
Processingとp5.jsとクリエイティブコーディングが大好きです。 めちゃくちゃ元気!