続・line()の魅力を引き出してみる
はじめに
前回、「line()の魅力を引き出してみる」という記事でp5.js()のline()の特徴やそれを使ったジェネラティブ・アートの作例を紹介しました。
今回もその続きで、前回の紹介例を発展させて更にline()の魅力を引き出す方法やline()に関連するp5.jsの描画特徴を紹介していきます。
多角形の中心と頂点を結ぶ
前回は多角形の頂点を外周を描くようにline()で結びました。
多角形の中心点と頂点を結ぶ線を追加してみます。単純に描く線の数が増えるので複雑な描画になることは想像できますね。
function setup() {
createCanvas(600, 600);
background(255);
stroke(255);
blendMode(DIFFERENCE);
noLoop();
}
function draw(){
for(let i=0;i<=width;i+=width/8){
for(let j=0;j<=height;j+=height/8){
line_polygon_2(i, j, int(random(20,40)), int(random(3,16)));
}
}
}
function line_polygon_2(x, y, size, point_num){
let cx = [];
let cy = [];
for(let i=0;i<point_num;i++){
let theta = TAU/point_num*i;
cx.push(0.5 * size * cos(theta));
cy.push(0.5 * size * sin(theta));
}
push();
translate(x, y);
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], cx[(i+1)%point_num], cy[(i+1)%point_num]);
}
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], 0, 0);
}
pop();
}
印象がずいぶん変わりました。ここまで複雑なのにline()だけで描けるのが不思議ですね。
多角形の中心点と頂点を結ぶ線はline(cx[i], cy[i], 0, 0)で描いています。line_polygon_2()関数の中でtranslate(x, y)しているので、原点が多角形の中心点になっているからです。
また、多角形の外周と多角形の中心点と頂点を結ぶ線を描く際に、それぞれでstrokeWeight()とstrokeCap()をランダムにしているので、より描かれる形の複雑度が増していると思います。
描画を更に重ねる
draw()の中のfor文を次のようにして、描画を重ねてみます。
for(let i=0;i<=width;i+=width/8){
for(let j=0;j<=height;j+=height/8){
line_polygon_2(i, j, int(random(20,40)), int(random(3,16)));
line_polygon_2(i, j, int(random(20,40)), int(random(3,16)));
}
}
単純にline_polygon_2()を二度呼び出しています。描く線の数も、ランダムな要素も二倍に増えるので、バリエーション豊かで実行する度におもしろい形に出会えますね。
ただ、複雑さが増して小さいと模様がわかりにくくなってきました。draw()を次のように変えて、一つだけ描くようにしてみます。
function draw(){
line_polygon_2(width*0.5, height*0.5, int(random(160,320)), int(random(3,16)));
line_polygon_2(width*0.5, height*0.5, int(random(160,320)), int(random(3,16)));
}
点線を用いる
line()で描画する線を点線にしてみます。p5.jsで点線を描く際にはdrawingContext.setLineDash()を使用します。
描画に使う関数を次のline_polygon_3()を用います。
function line_polygon_3(x, y, size, point_num){
let cx = [];
let cy = [];
for(let i=0;i<point_num;i++){
let theta = TAU/point_num*i;
cx.push(0.5 * size * cos(theta));
cy.push(0.5 * size * sin(theta));
}
push();
translate(x, y);
let linedash;
linedash = int(random(size*0.5));
drawingContext.setLineDash([linedash, linedash]);
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], cx[(i+1)%point_num], cy[(i+1)%point_num]);
}
linedash = int(random(size*0.5));
drawingContext.setLineDash([linedash, linedash]);
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], 0, 0);
}
pop();
}
わかりやすい画像を選んでみました。線が点線になるため、縞模様のような部分が浮かび上がったりします。
点線の特徴
drawingContext.setLineDash()を設定することで、line()の描画が点線になります。drawingContext.setLineDash([a, b, …])と線の長さ、間隔の長さを配列で引数に指定します。
drawingContext.setLineDash()の特徴を理解するために、次のコードを実行してみます。
function setup() {
createCanvas(600, 600);
background("#ffffff");
strokeWeight(50);
noLoop();
}
function draw(){
drawingContext.setLineDash([10, 100]);
strokeCap(ROUND);
line(100, 100, 500, 100);
drawingContext.setLineDash([5, 10, 10, 20]);
strokeCap(SQUARE);
line(100, 300, 500, 300);
drawingContext.setLineDash([5, 100]);
drawingContext.lineDashOffset = 5;
strokeCap(PROJECT);
line(100, 500, 500, 500);
}
それぞれのline()で描いた線が点線になっているのがわかります。drawingContext.setLineDash()への引数の指定によって点線の描かれ方が変わっています。
また、drawingContext.lineDashOffsetを指定すると一番下の線のように、点線の開始位置をずらすことができます。
点線にした場合でもstrokeCap()は適用されます。strokeCap(SQUARE)はdrawingContext.setLineDash()で指定通りの線の長さで描かれますが、strokeCap(ROUND)とstrokeCap(PROJECT)は実線で描いていた時の様に線の両端が線幅分飛び出します。そのため注意が必要です。次のコードでその線端での注意点を確認します。
function setup() {
createCanvas(600, 600);
background("#ffffff");
strokeWeight(50);
noLoop();
}
function draw(){
drawingContext.setLineDash([5, 10]);
strokeCap(ROUND);
line(100, 100, 500, 100);
drawingContext.setLineDash([5, 10]);
strokeCap(SQUARE);
line(100, 300, 500, 300);
drawingContext.setLineDash([5, 10]);
strokeCap(PROJECT);
line(100, 500, 500, 500);
}
strokeCap(ROUND)とstrokeCap(PROJECT)は線幅分の長さを考慮しないと、線が長くなっているため実線のようになっています。点線を描画する際のstrokeCap()の設定には気をつけましょう。
頂点をランダムにずらす
次の関数line_polygon_4()を使って、頂点の位置をランダムにずらしてみます。
function line_polygon_4(x, y, size, point_num){
let cx = [];
let cy = [];
for(let i=0;i<point_num;i++){
let theta = TAU/point_num*i + random(-1,1)*PI*0.1;
let rn = random(0.5,1.5);
cx.push(rn*0.5 * size * cos(theta));
cy.push(rn*0.5 * size * sin(theta));
}
push();
translate(x, y);
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], cx[(i+1)%point_num], cy[(i+1)%point_num]);
}
strokeWeight( int(random(size*0.05,size*0.75)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], 0, 0);
}
pop();
}
多角形の頂点を計算する際に、角度の揺らぎrandom(-1,1)*PI*0.1と半径の揺らぎrandom(0.5,1.5)を入れています。各頂点がランダムになり様々な形が生み出されます。
作品例
上で紹介したline()の魅力を引き出す方法4つで描いた形をカラーにして並べてみました。色をつけるとまた違った魅力になりますね。line()だけでもこれだけ様々な形を生み出せるのは楽しいですね。
おわりに
前回に引き続きline()の魅力を引き出す方法を紹介しました。紹介した内容でline()を用いて色々な作品を描くことができると思います。line()の面白さに気がついていただけたでしょうか。
皆さんもline()をうまく使いこなして、楽しくジェネラティブ・アートを作ってみて下さい。