この記事では書籍「世界一美しい錯視アート」に掲載されている「ビッグバン」という作品をProcessingを使って再現してみます。
ビッグバン
今回作成した錯視アート「ビッグバン」です。
書籍では「ぎらぎらしたり、動いて見えたりする。」と解説されています。自分としては、全体的にもわもわっとした印象があります。
描き方のポイント
扇形を中心に向けて縮小して並べる
この作品「ビッグバン」では、中心から外側に向けて白色と黒色の扇形が交互に拡がっていく図形が描かれています。このような図形は別記事「縮小していく線分を描く」に書いたことを応用すれば実現できます。つまり、外側から見ていくと、白色と黒色の扇形の大きさが中心に向かってどんどん縮小していきますが、このような図形は、等比数列の計算を行うことで実現することができます。詳細は別記事「縮小していく線分を描く」を見てください。
ここで扇形と書きましたが、実際に扇形で描いてみたところ、そのカーブが書籍にある「ビッグバン」のものと比べて円形に近い丸みを帯びすぎてしまうので、今回はベジエ曲線を用いてカーブを表現してみました。実際に描いてみると下図のようになります。
赤い線を描く
扇形を並べ終わったら、扇形の間に赤色(正確にはマゼンダ)の線を描きます。ただ、線は中心に向けて幅が小さくなっていくので、正確には三角形で描いています。
プログラムコード
今回作成した錯視アート「ビッグバン」のプログラムコードを載せておきます。
void setup() {
size(1000, 1000);
noStroke();
translate(width/2, height/2);
fill(0,175,204); // ターコイズブルー
ellipse(0, 0, width, width); // 背景の円を描く
float line_len = width/2.0 - width/12.0; // 線全体の長さ(収束点からの長さの初期値)
float segment_len_initial = width/50; // 線分の長さの初期値
float ratio = 1.0 - segment_len_initial / line_len; // 線分の縮小比率
float line_num = 20; // 中心から伸びていく図形の数
float th1 = radians(360.0/line_num); // 収束点での角度
for(int i=0; i<line_num; i++){
rotate(th1);
drawPies(line_len, segment_len_initial, ratio, th1); // 扇形を描いていく
}
float th2 = radians(0.5);
fill(228,0,127); // マゼンダ
rotate(th1/2.0);
for(int i=0; i<line_num; i++){
rotate(th1);
drawLine(line_len, th2); // 扇形の間にある線(正確には細長い三角形)を描く
}
}
void drawPies(
float line_len, // 線全体の長さ(収束点からの長さの初期値)
float segment_len_initial, // 線分の長さの初期値
float ratio, // 線分の縮小比率
float theta // 収束点での角度
){
float x; // 収束点からの長さ
float segment_len; // 線分の長さ
x = line_len;
segment_len = segment_len_initial;
float x1, y1, x2, y2, x3, y3, x4, y4;
int i = 0;
while(i<100){
// ベジエ曲線を用いて、扇形を描いていく
x1 = x * cos(theta/2);
y1 = x * sin(theta/2);
x2 = (x - segment_len) * cos(theta/2);
y2 = (x - segment_len) * sin(theta/2);
x3 = (x1+y1) * cos(theta/6);
y3 = (x1+y1) * sin(theta/6);
x4 = (x2+y2) * cos(theta/6);
y4 = (x2+y2) * sin(theta/6);
noStroke();
if (i % 2 == 0){
fill(0,0,0);
} else {
fill(255,255,255);
}
pushMatrix();
beginShape();
vertex(x1,y1);
bezierVertex(x3,y3,x3,-y3,x1,-y1);
vertex(x2, -y2);
bezierVertex(x4,-y4,x4,y4,x2,y2);
endShape(CLOSE);
popMatrix();
x = x - segment_len; // 収束点からの長さを更新
segment_len = segment_len * ratio; // 線分の長さを更新
i++;
}
}
void drawLine(
float line_len, // 線全体の長さ(収束点からの長さの初期値)
float theta // 収束点での角度
){
// 三角形を描く
noStroke();
pushMatrix();
beginShape();
vertex(line_len * cos(theta), line_len * sin(theta));
vertex(line_len * cos(-theta), line_len * sin(-theta));
vertex(0.0, 0.0);
endShape(CLOSE);
popMatrix();
}