まっそのせかい

やった事のメモとか

Processingで絵を描く

この記事はCCS Advent Calendar 2019の7日目の記事です。
昨日の記事:C++講座++ - yuma1338’s blog

お疲れ様です。CCSOBのまっそうめんです。
今年もCCSのアドベントカレンダーが行われるという事で、盛り上げるべく記事を書きます…!

衝動

突然ですが、何か絵を描きたくなりました。
この衝動をどうにかするため、まずProcessingをダウンロードして開きます。

f:id:massoumen:20191207001710p:plain

開いたらそこにコードを書きます。

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

実行ボタンを押すと別の画面が出てきます。

f:id:massoumen:20191206235455p:plain

絵が描けました。

Processingとジェネラティブアート

ProcessingというJavaベースのプログラミング言語があります。
線や図形などの描画機能が中心で、デザインやアート系のプログラミングが手軽にできるという特徴があります。
JavaScript版のp5.jsというライブラリもあるようです)

プログラムから絵を生成するので、パラメータなどの要素に乱数を使ったりする事で同じプログラムから様々な絵を作れたりもします。
(このような作品をジェネラティブアートと呼んだりするようです)

例えば先ほどのプログラムの場合、パラメータa, b, c, dcolorR, 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));

f:id:massoumen:20191207010519p:plain f:id:massoumen:20191207010526p:plain f:id:massoumen:20191207010905p:plain

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

f:id:massoumen:20191206235307p:plain

動くものも描けます。

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

f:id:massoumen:20191207023405g:plain

目が回る~~~

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

f:id:massoumen:20191207015541p:plain

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

f:id:massoumen:20191207020821p:plain

以上、「Processingで絵を描く」でした。
明日はこまつなさんの記事です。