Processingで絵を描く
この記事はCCS Advent Calendar 2019の7日目の記事です。
昨日の記事:C++講座++ - yuma1338’s blog
お疲れ様です。CCSOBのまっそうめんです。
今年もCCSのアドベントカレンダーが行われるという事で、盛り上げるべく記事を書きます…!
衝動
突然ですが、何か絵を描きたくなりました。
この衝動をどうにかするため、まずProcessingをダウンロードして開きます。
開いたらそこにコードを書きます。
int pointNum = 100000; int scale = 100; float a = 1.1; float b = 1.3; float c = 1.8; float d = 1.3; int colorR = 70; int colorB = 75; int colorG = 150; void setup() { size(800, 800); background(0, 0, 0); translate(width / 2, height / 2); drawCliffordAttractor(); } void drawCliffordAttractor() { blendMode(ADD); stroke(colorR, colorB, colorG); float x = 0; float y = 0; for(int i = 0; i < pointNum; i++) { point(scale * x, scale * y); float newX = sin(a * y) + c * cos(a * x); float newY = sin(b * x) + d * cos(b * y); x = newX; y = newY; } }
実行ボタンを押すと別の画面が出てきます。
絵が描けました。
Processingとジェネラティブアート
ProcessingというJavaベースのプログラミング言語があります。
線や図形などの描画機能が中心で、デザインやアート系のプログラミングが手軽にできるという特徴があります。
(JavaScript版のp5.jsというライブラリもあるようです)
プログラムから絵を生成するので、パラメータなどの要素に乱数を使ったりする事で同じプログラムから様々な絵を作れたりもします。
(このような作品をジェネラティブアートと呼んだりするようです)
例えば先ほどのプログラムの場合、パラメータa, b, c, d
やcolorR, colorG, colorB
に固定値ではなく乱数を与える事で様々な絵を生成できます。
float a = random(1, 2); float b = random(1, 2); float c = random(1, 2); float d = random(1, 2); int colorR = int(random(0, 150)); int colorB = int(random(0, 150)); int colorG = int(random(0, 150));
Twitter上で#processingや#generativeartといったタグ検索をするといろんな作品が上がっているので、見てみると楽しいかもしれません。
描いてみた
以下、労働で破壊された心を癒すべくいろいろ描いてみた奴です。
import java.util.ArrayList; int step = 5; float scale = 300f; void setup() { size(800, 800); background(255, 255, 255); translate(width / 2, height / 2); drawKochSnowflake(step, scale); } void drawKochSnowflake(int step, float scale) { ArrayList<PVector> points = new ArrayList<PVector>(); points.add(new PVector(sqrt(3) / 2, 0.5)); points.add(new PVector(-sqrt(3) / 2, 0.5)); points.add(new PVector(0, -1)); points.add(new PVector(sqrt(3) / 2, 0.5)); for(int i = 0; i < step; i++) { ArrayList<PVector> newPoints = new ArrayList<PVector>(); newPoints.add(points.get(0)); for(int j = 0; j < points.size() - 1; j++) { PVector triPoint1 = PVector.sub(points.get(j + 1), points.get(j)).div(3).add(points.get(j)); PVector triPoint3 = PVector.sub(points.get(j), points.get(j + 1)).div(3).add(points.get(j + 1)); PVector triPoint2 = PVector.sub(triPoint1, triPoint3).rotate(radians(60)).add(triPoint3); newPoints.add(triPoint1); newPoints.add(triPoint2); newPoints.add(triPoint3); newPoints.add(points.get(j + 1)); } points = newPoints; } fill(170, 255, 255); beginShape(); for(int i = 0; i < points.size() - 1; i++) { vertex(scale * points.get(i).x, scale * points.get(i).y); vertex(scale * points.get(i + 1).x, scale * points.get(i + 1).y); } endShape(); }
動くものも描けます。
float STEP = 2 * PI * 0.01; int loopNum = 4000; int iter = 0; void setup() { size(600, 600); } void draw() { background(255, 255, 255); drawSpiral(rad(STEP * iter)); iter++; } void drawSpiral(float scalar) { translate(width / 2, height / 2); for(int i = 0; i < loopNum; i++) { float theta = STEP * i; line(scalar * rad(theta) * cos(theta), scalar * rad(theta) * sin(theta), scalar * rad(theta + STEP) * cos(theta + STEP), scalar * rad(theta + STEP) * sin(theta + STEP)); } } float rad(float t) { float r = pow(1.05, t); return r; }
目が回る~~~
2Dだけでなく、3Dの描画もできます。
void setup() { size(800, 800, P3D); background(255, 255, 255); drawMoebiusLoop(); } void drawMoebiusLoop() { int divRNum = 10; int divTNum = 100; float stepR = 2.0f / divRNum; float stepT = PI / divTNum; float scale = 100; translate(width / 2, height / 2); rotateX(radians(45)); rotateZ(radians(45)); colorMode(HSB); beginShape(QUAD); for(int i = 0; i < divRNum; i++) { for(int j = 0; j < divTNum; j++) { float r1 = stepR * i - 1; float r2 = stepR * (i + 1) - 1; float t1 = stepT * j; float t2 = stepT * (j + 1); fill(255.0 / divRNum * i, 100, 255); vertex(scale * cos(2 * t1) * (r1 * cos(t1) + 2), scale * sin(2 * t1) * (r1 * cos(t1) + 2), scale * r1 * sin(t1)); vertex(scale * cos(2 * t2) * (r1 * cos(t2) + 2), scale * sin(2 * t2) * (r1 * cos(t2) + 2), scale * r1 * sin(t2)); vertex(scale * cos(2 * t2) * (r2 * cos(t2) + 2), scale * sin(2 * t2) * (r2 * cos(t2) + 2), scale * r2 * sin(t2)); vertex(scale * cos(2 * t1) * (r2 * cos(t1) + 2), scale * sin(2 * t1) * (r2 * cos(t1) + 2), scale * r2 * sin(t1)); } } endShape(); }
void setup() { size(800, 800, P3D); background(255, 255, 255); translate(450, 800); rotateX(radians(45)); rotateZ(radians(45)); rotateX(radians(45)); rotateY(radians(-45)); drawDoubleHelix(0, 330); drawDoubleHelix(PI, 220); } void drawDoubleHelix(float shift, float colorH) { float theta = 6 * PI; float scale = 250; float h = 1000; int divNum = 60; float stepT = theta / divNum; float stepH = h / divNum; stroke(0,0,0); noStroke(); colorMode(HSB, 360, 100, 100, 100); for(int i = 0; i < divNum; i++) { rotateZ(shift); translate(scale * rad(stepT * i) * cos(stepT * i), scale * rad(stepT * i) * sin(stepT * i), stepH * i); rotateZ(stepT * i); fill(colorH, 80.0 * (divNum - i) / divNum, 100, 50); box(80, 40, 10); rotateZ(-stepT * i); translate(-scale * rad(stepT * i) * cos(stepT * i), -scale * rad(stepT * i) * sin(stepT * i), -stepH * i); rotateZ(-shift); } } float rad(float t) { float r = pow(1.01, t); return r; }
以上、「Processingで絵を描く」でした。
明日はこまつなさんの記事です。