1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Processing描画命令使ったGenerative Art例

Last updated at Posted at 2024-04-12

はじめに

Processingのリファレンス+αとして、Generative Artっぽいものを目指したサンプルです。

リファレンス参照
https://processing.org/reference#shape-2d-primitives

リファレンス(abc)順にサンプル載せます。

円弧 arc

これらの円弧の長さは、すべて同じ。

Processing
size(800, 800);
background(255);
float r = 390;
noFill();
for (float n=0.5; n<2.01; n+=0.1) {
  arc(400, 400, r/n, r/n, 0, PI*n);
}

image.png

Processing
size(800, 800);
background(0);
float r = 400;
fill(255, 255, 0);
arc(400, 400, r, r, PI/4, PI*7/4);

image.png

円circle

乱数でたくさん描く。

Processing
void setup(){
  size(800, 800);
}

void draw() {
  float x, y, r;
  x = random(width);
  y = random(height);
  r = random(50, 100);
  fill(random(255));
  circle(x, y, r);
}

image.png

再帰処理で描く。

Processing
void setup() {
  size(800, 800);
  func(400, 400, 800, 8);
}

void func(float x, float y, float r, int n) {
  if (0<n) {
    fill(n%2*255);
    circle(x, y, r);
    func(x-r/4, y, r/2, n-1);
    func(x+r/4, y, r/2, n-1);
  }
}

image.png

楕円ellipse

乱数でたくさん描く。

Processing
void setup(){
  size(800, 800);
}

void draw() {
  float x, y, w, h;
  x = random(width);
  y = random(height);
  w = random(50, 200);
  h = random(50, 200);
  fill(random(255));
  ellipse(x, y, w, h);
}

image.png

回転させながら、縮小する。

Processing
size(800, 800);
translate(400, 400);

for (int n=0; n<50; n++) {
  fill(255-n*4);
  ellipse(0, 0, 800, 400);
  scale(0.9);
  rotate(PI/22);
}

image.png

線line

Processing
size(800, 400);

for (int y=0; y<400; y+=10) {
  line(  0, y, 800-y*2,   0);
  line(800, y, 800-y*2, 400);
}

image.png

点point

1ピクセルの点描ですが、直径1の円として描かれるため、希望の色になりません。noSmooth()を指定することで、希望の色で点描できます。
※set()やpixels[]使うと速くできます。

Processing
size(800, 400);
noSmooth();

for (int y=0; y<400; y+=2) {
  for (int x=0; x<800; x+=2) {
    stroke(x/4,y/2,0);
    point(x,y);
  }
}

image.png

四角quad

return to squareをオマージュ

Processing
size(800, 800);
noFill();
float a=200, b=600;
for (int n=0; n<150; n+=5) {
  quad(a+n, a+n,
       b+n, a-n,
       b-n, b-n,
       a-n, b+n);
  quad(a-n, a+n,
       b-n, a-n,
       b-n, b+n,
       a+n, b-n);
}

image.png

長方形、矩形rect

長方形が描けて、角丸にする機能もあります。
参考までに、正円を赤で書きました。
角丸の値は、長方形の短辺の半分より大きくすることはできず、無視されます。以下のサンプルの場合、幅400に対して、角丸の値は200までしか認識されません。

Processing
size(600, 600);
float x=100, y=100, w=400, h=400;
rect(x,y,w,h);
rect(x,y,w,h,50);
rect(x,y,w,h,100);
rect(x,y,w,h,150);
rect(x,y,w,h,200);

stroke(255,0,0);
circle(300,300,400);

image.png

Processing
size(800, 800);
translate(400, 400);
fill(255,255,255,10);
for (int x=0; x<=400; x+=10) {
  stroke(x, 0, 255);
  int y = 400-x;
  rect(-x, -y, x*2, y*2);
}

image.png

正方形square

比は1/√2です。

Processing
size(800, 800);
translate(400, 400);

for (int n=0; n<20; n++) {
  square(-400, -400, 800);
  rotate(PI/4);
  scale(1/sqrt(2));
}

image.png

三角形triangle

Processing
void setup() {
  size(800, 800);
  noStroke();
  func(800, 800, 800, 8);
}

void func(float x, float y, float h, int n) {
  if (0<n) {
    fill(0);
    triangle(x, y, x, y-h, x-h, y);
    func(x-h/2, y+h/2, h/2, n-1);
    func(x+h/2, y-h/2, h/2, n-1);
    func(x-h/2, y-h/2, h/2, n-1);
  }
}

image.png

多角形beginShape,endShape,vertex

beginShape
 vertex(頂点1)
 vertex(頂点2)
 ...
endShape
のように使う。
このとき、頂点をどのように描画するか、指示ができる。
指定なし:多角形
POINTS 複数の点
LINES 複数の線
TRIANGLES 複数の三角形
TRIANGLE_STRIP 帯状の連続した三角形
TRIANGLE_FAN 扇形の三角形
QUADS 複数の四角形
QUAD_STRIP 帯状の連続した四角形
※それぞれ対応する数字がある。

Processing
println(POINTS);//3
println(LINES);//5
println(TRIANGLES);//9
println(TRIANGLE_STRIP);//10
println(TRIANGLE_FAN);//11
println(QUADS);//17
println(QUAD_STRIP);//18

多角形

Processing
size(300, 300);
translate(150, 150);

beginShape();
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

LINES

Processing
size(300, 300);
translate(150, 150);

beginShape(LINES);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

TRIANGLES

Processing
size(300, 300);
translate(150, 150);

beginShape(TRIANGLES);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

TRIANGLE_STRIP

Processing
size(300, 300);
translate(150, 150);

beginShape(TRIANGLE_STRIP);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

TRIANGLE_FAN

Processing
size(300, 300);
translate(150, 150);

beginShape(TRIANGLE_FAN);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

QUADS

Processing
size(300, 300);
translate(150, 150);

beginShape(QUADS);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

QUAD_STRIP

Processing
size(300, 300);
translate(150, 150);

beginShape(QUAD_STRIP);
for (float t=0; t<2*PI; t+=PI/6) {
  vertex(100*cos(t), 100*sin(t));
}
endShape();

image.png

輪郭beginContour,endContour

多角形を描く際に、中をくりぬく。飛び出た場合は、図のようになる。

Processing
size(400,400);
translate(200, 200);

beginShape();
  // 外側時計回り
  vertex( 0, -170);
  vertex(150, 90);
  vertex(-150, 90);

  // 内側反時計回り
  beginContour();
  vertex(-150, -90);
  vertex(0, 170);
  vertex(150, -90);
  endContour();
endShape(CLOSE);

image.png

二次ベジェ曲線quadraticVertex

制御点は3つ必要です。最初の制御点は、直前の命令vertexの終点(0,200)になるので、quadraticVertexでは、2点(制御点と終点)の指定をします。サンプルでは、視点を終点を同一にし、制御点をずらして描画しています。
モアレ軽減のため、半透明使ってます。

Processing
size(400, 400);
noFill();
stroke(0,0,0,128);

beginShape();
  vertex(0, 200);
  for(float y=-200; y<600;y+=20){
    quadraticVertex(200, y , 400, 200);
    quadraticVertex(200, y+10, 0, 200);
  }
endShape();

image.png

二次ベジェ曲線はlineで示したサンプルと一致します。

Processing
size(800, 400);
noFill();

for (int y=0; y<400; y+=10) {
  line(  0, y, 800-y*2,   0);
  line(800, y, 800-y*2, 400);
}

stroke(255,0,0);
beginShape();
  vertex(0, 400);
  quadraticVertex(0, 0, 800, 0);
  quadraticVertex(800, 400, 0, 400);
endShape();

image.png

三次ベジェ曲線bezier

制御点は4つ必要です。始点と終点を固定し、1つの制御点を、ずらして描いています。

Processing
size(800, 400);
noFill();
stroke(0,0,0,128);
for(int y=-300; y<500; y+=20) {
  bezier(  0, 200,
         300,   y,
         500, 400,
         800, 200);
}

image.png

bezierVertex

4つの制御点が必要なところを、始点を直前の命令(vertexなど)とすることで、3点を指定すれば良い方法です。イラレのような、連続したベジェ曲線に使えそうです。
ここでは、2本のベジェ曲線でハートを描きました。

Processing
size(800, 600);
translate(400, 150);

beginShape();
  vertex(0, 0);
  bezierVertex(300, -200, 400, 200, 0, 400);
  bezierVertex(-400, 200, -300, -200, 0, 0);
endShape();

image.png

分割数制御bezierDetail

1~20の範囲で分割数を制御。P3Dのみ対応。出番は低そう。

Processing
size(800, 600, P3D);
translate(400, 150);

bezierDetail(20);
beginShape();
  vertex(0, 0);
  bezierVertex(300, -200, 400, 200, 0, 400);
  bezierVertex(-400, 200, -300, -200, 0, 0);
endShape();

bezierDetail(5);
scale(0.8);
beginShape();
  vertex(0, 0);
  bezierVertex(300, -200, 400, 200, 0, 400);
  bezierVertex(-400, 200, -300, -200, 0, 0);
endShape();

bezierDetail(3);
scale(0.8);
beginShape();
  vertex(0, 0);
  bezierVertex(300, -200, 400, 200, 0, 400);
  bezierVertex(-400, 200, -300, -200, 0, 0);
endShape();

image.png

bezierPoint

0<t<1で
tを変化させたときに、どうなるか、
ベジェ曲線の理解を深めるのに使えそうです。

Processing
size(800, 600);
translate(400, 150);

int x1=  0, y1=   0;
int x2=300, y2=-200;
int x3=400, y3= 200;
int x4=  0, y4= 400;

bezier(x1, y1,  x2, y2,  x3, y3, x4, y4);
bezier(x4, y4, -x3, y3, -x2, y2, x1, y1);

float x,y;
strokeWeight(20);

for(float t=0; t<=1.001; t+=0.1){
  x = bezierPoint(x1, x2, x3, x4, t);
  y = bezierPoint(y1, y2, y3, y4, t);
  point(x,y);
}

image.png

接線bezierTangent

tan正接、接線の向きが得られます。
ここでは、正規化(normalize)してから使いました。

また、接線を90度回転して法線が描けます。
(x,y)ベクトルを90度回すということは,
(y,-x)に変換することです。

Processing
size(800, 600);
translate(400, 150);

int x1=  0, y1=   0;
int x2=300, y2=-200;
int x3=400, y3= 200;
int x4=  0, y4= 400;

bezier(x1, y1,  x2, y2,  x3, y3, x4, y4);
bezier(x4, y4, -x3, y3, -x2, y2, x1, y1);

float x,y,tanx,tany;
for(float t=0; t<=1.001; t+=0.1){
  x = bezierPoint(x1, x2, x3, x4, t);
  y = bezierPoint(y1, y2, y3, y4, t);
  tanx = bezierTangent(x1, x2, x3, x4, t);
  tany = bezierTangent(y1, y2, y3, y4, t);
  PVector v = new PVector(tanx,tany);
  v.normalize();
  stroke(255,0,0);
  line(x-v.x*50,
       y-v.y*50,
       x+v.x*50,
       y+v.y*50);
  stroke(0,0,255);
  line(x,
       y,
       x+v.y*50,
       y-v.x*50);
}

image.png

Catmull-Romスプラインcurve

スプライン曲線とは指定した点の上を通る曲線のことです。
曲線の引き方にも種類があり、ProcessingではCatmull-Romをcurve命令で実装されています。
以下では、5点を指定し、これら5点を通る曲線を描いています。
通常1-2-3-4と点を指定した場合、2-3の間しか曲線が引けませんが、1-1-2-3と指定したり、3-4-5-5と重ねて指定することで、始点と終点を通す曲線が描けます。

Processing
size(600, 400);
noFill();

int x1=100, y1=100;
int x2=100, y2=300;
int x3=300, y3=300;
int x4=300, y4=100;
int x5=500, y5=100;

line(x1, y1, x2, y2);
line(x2, y2, x3, y3);
line(x3, y3, x4, y4);
line(x4, y4, x5, y5);

stroke(255, 0, 0);
curve(x1, y1, x1, y1, x2, y2, x3, y3);
stroke(0);
curve(x1, y1, x2, y2, x3, y3, x4, y4);
stroke(0, 0, 255);
curve(x2, y2, x3, y3, x4, y4, x5, y5);
stroke(0, 255, 0);
curve(x3, y3, x4, y4, x5, y5, x5, y5);

image.png

下はbezierのサンプル座標と同じ座標でcurveを使って、描いたものです。
bezierとcurveの指定点を通る通らないの特徴がでています。

Processing
size(800, 500);
noFill();

for(int y=-300; y<500; y+=20) {
  stroke(0,0,0,128);
  curve(   0, 200,
           0, 200,
         300,   y,
         500, 400);
  stroke(255,0,0,128);
  curve(   0, 200,
         300,   y,
         500, 400,
         800, 200);
  stroke(0,0,255,128);
  curve( 300,   y,
         500, 400,
         800, 200,
         800, 200);
}

image.png

curveVertex

長いスプライン曲線を描くなら、こっちの書き方がシンプルでしょう。

Processing
size(600, 400);
noFill();

int x1=100, y1=100;
int x2=100, y2=300;
int x3=300, y3=300;
int x4=300, y4=100;
int x5=500, y5=100;

line(x1, y1, x2, y2);
line(x2, y2, x3, y3);
line(x3, y3, x4, y4);
line(x4, y4, x5, y5);

stroke(255, 0, 0);

beginShape();
  curveVertex(x1, y1);
  curveVertex(x1, y1);
  curveVertex(x2, y2);
  curveVertex(x3, y3);
  curveVertex(x4, y4);
  curveVertex(x5, y5);
  curveVertex(x5, y5);
endShape();

image.png

curveTightness

スプライン曲線を変えることができる。仕組みは未調査。引数はいくつでも良いが、リファレンスでは-5~5を使っていた。使う場面が思いつかないが、-1~1あたりなら丸みの制御で使えそう。
-1は大きく膨らむ
0は無指定と同じ
1は直線と同じ
2は曲線がねじれる

Processing
int x1=100, y1=100;
int x2=100, y2=300;
int x3=300, y3=300;
int x4=300, y4=100;
int x5=500, y5=100;

void setup(){
  size(600, 500);
  noFill();
  
  for(int t=-5; t<=5; t++){
    stroke(128+20*t, 0, 0);
    func(t);
  }
  
  stroke(255,255,255);
  line(x1, y1, x2, y2);
  line(x2, y2, x3, y3);
  line(x3, y3, x4, y4);
  line(x4, y4, x5, y5);
}

void func(float t){
  curveTightness(t);
  beginShape();
    curveVertex(x1, y1);
    curveVertex(x1, y1);
    curveVertex(x2, y2);
    curveVertex(x3, y3);
    curveVertex(x4, y4);
    curveVertex(x5, y5);
    curveVertex(x5, y5);
  endShape();
}

image.png

範囲を変えた場合
  for(float t=-1; t<=1; t+=0.4){

image.png

curveDetail

1~20の範囲で分割数を制御。P2Dのみ対応。出番は低そう。

Processing
int x1=100, y1=100;
int x2=100, y2=300;
int x3=300, y3=300;
int x4=300, y4=100;
int x5=500, y5=100;

void setup(){
  size(600, 500, P2D);
  noFill();
  
  stroke(0, 0, 0);
  func(1);
  stroke(255, 0, 0);
  func(2);
  stroke(0, 0, 255);
  func(4);
}

void func(int d){
  curveDetail(d);
  beginShape();
    curveVertex(x1, y1);
    curveVertex(x1, y1);
    curveVertex(x2, y2);
    curveVertex(x3, y3);
    curveVertex(x4, y4);
    curveVertex(x5, y5);
    curveVertex(x5, y5);
  endShape();
}

image.png

curvePoint

bezierと同じなので割愛

curveTangent

bezierと同じなので割愛

直方体box

Processing
void setup() {
  size(400, 400, P3D);//OPENGLでも動く
}

void draw() {
  background(255);
  translate(200, 200, 0);
  rotateY(frameCount*0.01);
  noFill();
  box(150);
  box(200,100,200);
}

image.png

球sphere

sphereDetailのデフォルトは30
sphereDetail(水平分割数,垂直分割数)でも使える。

Processing
void setup() {
  size(800, 800, P3D);
}

void draw() {
  background(255);
  translate(400, 400, 0);
  rotateY(frameCount*0.01);
  noFill();
  sphereDetail(16);
  sphere(300);
}

image.png

3D

Processing
void setup() {
  size(800, 800, P3D);
  noStroke();
}

void draw() {
  background(255);
  camera(0, -100, 200,
         0, 0, 0,
         0, 1, 0);
  lights();

  for (float z=-100; z<101; z+=50) {
    for (float x=-100; x<101; x+=50) {
      fill(random(255),random(255),random(255));
      pushMatrix();
        translate(x, 0, z);
        sphere(20);
      popMatrix();
    }
  }
}

image.png

ノイズnoise

randomとは異なり、滑らかに変化する乱数(0~1)が得られる。
実装はPerlin関数。
引数の数で1次元,2次元,3次元が選べる。

Processing
float th;

void setup() {
  size(800, 800);
}

void draw() {
  background(255);
  for (int y=0; y<800; y+=10) {
    for (int x=0; x<800; x+=10) {
      th = noise(x*0.01, y*0.01, frameCount*0.02);
      th *= 4*PI;
      line(x, y, x+20*cos(th), y+20*sin(th));
    }
  }
}

image.png

その他

rect命令の角丸機能は、もしかして、iPhoneの角かも!と思いましたが、違いました。
rect(100,100,400,400,169);
の時一番近くなりますが、一致はしません。

Processingの入出力について

書き出し 読み込み 備考
JPG o o save("a.jpg")
loadImage()
PNG o o save("a.png")
loadImage()
SVG o o import processing.svg.*;
loadShape()
OBJ o import nervoussystem.obj.*
loadShape()
PDF o x import processing.pdf.*;

Sprine系の曲線をSVGやPDFで保存した場合でも、内部でベジェに変換されて保存されます。円もしかりです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?