1. ホーム
  2. 錯視アート
  3. 渦巻きワープ

この記事では書籍「世界一美しい錯視アート」に掲載されている「渦巻きワープ」という作品をProcessingを使って再現してみます。

渦巻きワープ

今回作成した錯視アート「渦巻きワープ」です。

渦巻きワープ

書籍では「主観色が渦巻き状に走るように見える。」と解説されています。そういわれると、主観色(青っぽい色?)が走っているようにも見えるような・・・。

もしかしたら、この作品をうまく再現できていないのかもしれません。

描き方のポイント

白黒の格子模様をどう作っていくか

この作品でポイントとなることは、白黒の格子模様をどう作っていくかだと思います。ここではその手順を説明します。

1.まず、白色の背景の上に黒色の線幅が広がっていく対数螺旋を描いていきます。線幅が広がっていく対数螺旋については、別記事「螺旋を描く」で解説していますので、詳細はそちらをご覧ください。

線幅が広がっていく対数螺旋

2.次に、頂点が図の中心に位置する、白色と黒色の二等辺三角形を交互に描いていくことで、以下のような図形を用意します。

この図形をその前に描いた対数螺旋に重ねて描きますが、その際、

 blendMode(DIFFERENCE);

を指定しておきます。その結果、

  • 白色と白色が重なる部分は黒色
  • 白色と黒色が重なる部分は白色
  • 黒色と黒色が重なる部分は黒色

となります。実際に重ねてみた結果、以下のように格子模様が描けます。

格子模様ができる

画像をぼかす

格子模様はぼかしが入っています。画像のぼかしは

filter(BLUR,3);

をプログラムコードに入れることで実現できます。

ぼかした結果

なお、filter関数の2番目の引数の値を変えることで、ぼかし効果の強さを調整できます。今回はいくつかの値を入れてみて、一番しっくりくるものを選びました。

黒色部分の中心に色を入れる

ここまで出来たら、後は黒色の部分の中心に色を入れるだけです。入れる位置は対数螺旋を描く関数を少し調整することで作ることができます。

プログラムコード

今回作成した錯視アート「渦巻きワープ」のプログラムコードを載せておきます。

void setup() {
  size(1000, 1000);
  
  background(255,255,255);
  translate(width/2, height/2);

  int spiral_num = 60; // 螺旋の数
  float spiral_angle = radians(360 / spiral_num); // 螺旋の中心での角度

  // 黒色の螺旋を描く
  fill(0,0,0);
  for(int i=0; i<spiral_num/2; i++){
    rotate(2*spiral_angle);
    drawLogSpiral(spiral_angle);
  }
 
  noStroke();
  blendMode(DIFFERENCE);
  int tri_num = 180; // 二等辺三角形の数
  float tri_angle = radians(360/tri_num); // 二等辺三角形の頂点の角度
  for(int i=0; i<tri_num; i++){
    rotate(tri_angle);
    if ( i%2 == 0 ){
      fill(255,255,255);
    } else {
      fill(0,0,0);
    }
    triangle(0.0,0.0,
             width * sqrt(2.0),0.0,
             width * sqrt(2.0) * cos(tri_angle), width * sqrt(2.0) * sin(tri_angle));
  }  
  blendMode(BLEND);  // blendModeをデフォルトに戻す

  filter(BLUR,3); // ぼかし効果を入れる
  
  // 黒色の部分の中心位置に2,3ピクセル分、色を乗せる
  noFill();
  for(int i=0; i<spiral_num; i++){
    rotate(spiral_angle);
    drawPoints(spiral_angle, tri_angle);
  }
}

// 螺旋を描く関数
void drawLogSpiral(
  float spiral_angle // 螺旋の中心での角度
){
  int STEP_num = 2000;
  float theta = 0;
  float scalar = height;
  beginShape();
  for(int i=0; i<STEP_num; i++){
    vertex(scalar * rad2(theta) * cos(-theta),scalar * rad2(theta) * sin(-theta));
    theta -= spiral_angle;
  }
  for(int i=0; i<STEP_num; i++){
    vertex(scalar * rad2(theta + spiral_angle) * cos(-theta),scalar * rad2(theta + spiral_angle) * sin(-theta));
    theta += spiral_angle;
  }
  endShape();
}

// 動径の大きさを定める関数
float rad2(float t){
  float r = pow(1.5, t);
  return(r);
}

// 黒色の部分の中心位置に数ピクセル分色を重ねる関数
void drawPoints(
  float spiral_angle, // 螺旋の中心での角度
  float tri_angle // 二等辺三角形の頂点の角度
){
  int STEP_num = 200;
  float theta = spiral_angle/2.0 - tri_angle/2.0;
  float scalar = height;
  beginShape();
  for(int i=0; i<STEP_num; i++){
    for(int j=0; j<2; j++){
      for(int k=0; k<2; k++){
        fill(random01(), random01(), random01());
        rect(scalar * rad2(theta) * cos(-theta - spiral_angle/2.0) + j-1,scalar * rad2(theta) * sin(-theta - spiral_angle/2.0)+k-1, 2.0*rad2(theta), 2.0*rad2(theta));
      }
    }
    theta -= 2.0*tri_angle;
  }
  endShape();
}

// ランダムに0か255を与える関数
float random01(){
  float num = random(1);
  if( num < 0.5 ) {
    return 0.0;
  } else {
    return 255.0;
  }
}

コメントを残す