おはよう。@bioerrorlogです。
ProcessingによるGenerative Art作品
10作目を記録します。
自作品まとめはこちら: www.bioerrorlog.work
Output
フル解像度/その他出力パターンはこちら:
Generative_10 - BioErrorLog - pixiv
Material
使用言語: Processing 3.5.3
Processingというプログラミング言語に聞き覚えがない、という方は是非こちらをご参考ください:
www.bioerrorlog.work
Source Code
GitHubはこちら
/* Modified from: Daniel Shiffman Coding Challenge #24: Perlin Noise Flow Field https://youtu.be/BjoM9oKOAKY https://github.com/CodingTrain/website/tree/master/CodingChallenges/CC_024_PerlinNoiseFlowField */ FlowField flowfield; ArrayList<Particle> particles; void setup() { size(1920, 1080); flowfield = new FlowField(10); // 引数からflowfieldを構成するベクターの数が算出・定義される flowfield.update(); particles = new ArrayList<Particle>(); for (int i = 0; i < 10000; i++) { // 生成するParticlesの数を指定 PVector start = new PVector(random(width), random(height)); particles.add(new Particle(start, random(2, 8))); } background(255); } void draw() { flowfield.update(); for (Particle p : particles) { p.follow(flowfield); p.run(); } } void keyPressed(){ /* ENTERキー押下: 画像を保存する BACKSPACEキー押下: リセット */ if (keyCode == ENTER){ saveFrame("generative_10_####.png"); } if (keyCode == BACKSPACE){ setup(); } } public class FlowField { /* 画面に配置されるベクターの集合体 Particlesの動きに力を加える */ PVector[] vectors; int cols, rows; float inc = 0.1; float zoff = 0; int scl; FlowField(int res) { scl = res; cols = floor(width / res) + 1; rows = floor(height / res) + 1; vectors = new PVector[cols * rows]; } void update() { // flowfield状態を定義 // フレームごとに呼び出される float xoff = 0; for (int y = 0; y < rows; y++) { float yoff = 0; for (int x = 0; x < cols; x++) { float angle = noise(xoff, yoff, zoff) * radians(180); // ここで各ベクターの角度を定義 PVector v = PVector.fromAngle(angle); // Flowfieldを構成するベクター v.setMag(1); // 各ベクターの大きさを定義 int index = x + y * cols; vectors[index] = v; xoff += inc; } yoff += inc; } zoff += 0.004; } } public class Particle { /* ひとつの粒子 動きはflowfieldのベクターから影響を受ける */ PVector pos; PVector vel; PVector acc; PVector previousPos; float maxSpeed; Particle(PVector start, float maxspeed) { maxSpeed = maxspeed; pos = start; vel = new PVector(0, 0); acc = new PVector(0, 0); previousPos = pos.copy(); } void run() { update(); edges(); show(); } void update() { pos.add(vel); vel.limit(maxSpeed); vel.add(acc); acc.mult(0); } void applyForce(PVector force) { acc.add(force); } void show() { // 描画処理 stroke(10, 2); // ここで線の色調整 strokeWeight(1); // ここで線の太さ調整 line(pos.x, pos.y, previousPos.x, previousPos.y); updatePreviousPos(); } void edges() { // 画面端の処理 if (pos.x > width) { pos.x = 0; updatePreviousPos(); } if (pos.x < 0) { pos.x = width; updatePreviousPos(); } if (pos.y > height) { pos.y = 0; updatePreviousPos(); } if (pos.y < 0) { pos.y = height; updatePreviousPos(); } } void updatePreviousPos() { this.previousPos.x = pos.x; this.previousPos.y = pos.y; } void follow(FlowField flowfield) { // Flowfieldから受ける力を適用 int x = floor(pos.x / flowfield.scl); int y = floor(pos.y / flowfield.scl); int index = x + y * flowfield.cols; PVector force = flowfield.vectors[index]; applyForce(force); } }
Discussion
私はDaniel ShiffmanのYoutubeチャンネルThe Coding Trainが大好きです。
今回はその動画の一つである、Perlin Noise Flow Fieldの実装コードを参考にしました。
今回のProcessingコードは、Flowfield
とParticle
のふたつのクラスを持ちます。
おかげで少し長いコードになってますが、簡単に応用できるが良いところです。
Flowfield
クラスは、画面に格子状に配置されるベクターを定義しています。
このパラメータを操作すれば、自由にモデルの流れを制御することができます。
Particle
クラスは、Flowfield
の流れの影響を受ける一つ一つの粒子を定義しています。
粒子の数や描画方法、大きさや色を自由に操作することができます。
今回は元のコード大して変わらない簡単な定義でモデルを走らせましたが、工夫次第でいくらでも遊べそうな予感に、胸が膨らみます。
See also
Reference
Coding Challenge #24: Perlin Noise Flow Field - Daniel Shiffman
Coding Challenge #24: Perlin Noise Flow Field - Daniel Shiffman - GitHub