line()の魅力を引き出してみる
はじめに
p5.jsでクリエイティブ・コーディングをやる中でline()は、初めに学ぶ描画関数だと思います。機能はシンプルで指定した二点間に線を引くというもの。
シンプルが故に時間が経つと忘れられがちな関数だと思います。皆さんの中にもline()って最近使ってないなと思い当たる方もいるのではないでしょうか?
今回、p5.jsのline()の性質・特徴を改めて振り返ります。更にline()の魅力を活かしたジェネラティブ・アートの作例を解説していきます。これを機会に皆さんもline()を使って作品を作ってみてはいかがでしょうか。
line()の性質
基本描画
まずは今回使うline()の性質を改めて見てみましょう。次のコードを使って説明していきます。
function setup() {
createCanvas(600, 600);
background("#ffffff");
noLoop();
}
function draw(){
line(0, 0, 200, 200);
stroke("#ff0000");
line(100, 300, 300, 300);
stroke("#00ff00");
strokeWeight(50);
line(500, 100, 500, 500);
}
line()はある二点を4つの引数で指定し、その二点間に線を引くことができます。ここではline(0, 0, 200, 200)で(0, 0)と(200, 200)に線を引きました。デフォルト設定では線色は黒、線幅は1pixelとなっています。
線の色を変えたい場合は、stroke()で色を指定します。stroke("#ff0000")で線の色を赤に変更できます。
線の幅を変えたい場合は、strokeWeight()で線幅を指定します。strokeWeight(50)で線の幅を50pixelに変更できます。
線端の変更 strokeCap()
line()は線の端を変えることができます。次のコードを使って説明していきます。
function setup() {
createCanvas(600, 600);
background("#ffffff");
strokeWeight(50);
noLoop();
}
function draw(){
strokeCap(ROUND);
line(100, 100, 500, 100);
strokeCap(SQUARE);
line(100, 300, 500, 300);
strokeCap(PROJECT);
line(100, 500, 500, 500);
}
端の形がわかりやすいように線幅は50pixelにしています。
線端の形を変えたい場合は、strokeCap()で線端の形を指定します。p5.jsではROUND, SQUARE, PROJECTの3種類が用意されています。デフォルトではstrokeCap(ROUND)となっています。
それぞれの形を見ると
・strokeCap(ROUND)は線端が丸
・strokeCap(SQUARE)は線端が四角
・strokeCap(PROJECT)は線端が四角
となっています。
それぞれの線の長さをよく見ると異なっているのがわかるかと思います。次の画像ではx座標が100と500の位置に赤い線を引いています。
それぞれの長さを見ると
・strokeCap(ROUND)は線端はみ出る
・strokeCap(SQUARE)は線端がはみ出ない
・strokeCap(PROJECT)は線端がはみ出る
となっています。
line()を描く際にはstrokeCap()のROUND, SQUARE, PROJECTの特徴を理解しておくとline()の魅力を引き出すことができると思います。この特徴は思えておいて損はないのではないでしょうか。
line()の作例
ここからはline()を使った作例の解説をしていきます。今回は次のような作例を作っていきます。
この作例では2つポイントがあります。
・line()で多角形を描く
・blendMode(DIFFERENCE)とstrokeCap()で線の重なりの特徴を出す
この2つについて詳しく解説をしていきます。
line()で多角形を描く
line()で多角形を描いてみましょう。今回は次のようなline_polygon()という関数を作りました。
function line_polygon(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);
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], cx[(i+1)%point_num], cy[(i+1)%point_num]);
}
pop();
}
はじめのfor文で多角形の頂点を求めて、座標をcx, cyという配列に格納しています。多角形の頂点は360°(TAU)を頂点数(point_num)で均等に割り、x座標をcos()、y座標をsin()で計算します。
2個目のfor文でline()で多角形を描いています。配列cx, cyに入っている座標からi番目とi+1番目の頂点の間にline()で線を描画します。コードで(i+1)%point_numとなっているのは最後の頂点とはじめの頂点の間に線を引くためです。例えば六角形であれば、最後はi=5となるので5番目と0番目の頂点の線を引きます。for文の中で最後の0番目を(i+1)%point_num→(5+1)%6=0と計算上なるようにしています。
line_polygon()を用いれば、次のように多角形を描くことができるようになります。
function setup() {
createCanvas(600, 600);
background(255);
strokeWeight(20);
noLoop();
}
function draw(){
line_polygon(300, 100, 150, 3);
line_polygon(300, 300, 150, 4);
line_polygon(300, 500, 150, 5);
}
三角形、四角形、五角形を描いた例になります。
blendMode(DIFFERENCE)とstrokeCap()
上で描いた多角形をアレンジしていきます。blendMode(DIFFERENCE)とstrokeCap()を用いていきます。次のコードがアレンジしたものになります。
function setup() {
createCanvas(600, 600);
background(255);
stroke(255);
strokeWeight(20);
noLoop();
}
function draw(){
blendMode(DIFFERENCE);
strokeCap(ROUND);
line_polygon(300, 100, 150, 3);
strokeCap(SQUARE);
line_polygon(300, 300, 150, 4);
strokeCap(PROJECT);
line_polygon(300, 500, 150, 5);
}
実行した結果が下のようになります。
blendMode(DIFFERENCE)とすることで、描画モードが差分になります。既に描画されている色と、その上から描く色の差分の絶対値が画面に描画されるモードになります。
上のコードでは、初めに背景色が白(255)に設定されます。そこに線色が白(255)で線を描画するため、白と白の差分の絶対値である黒(abs(255-255)=0)で線が描かれます。
多角形を描く際には頂点の所で線が重なるため、差分により黒で描かれた線の上に白い線を描くことになります。このとき、既に描かれた黒(0)と線色の白(255)の差分の絶対値は白(abs(0-255)=255)となります。
これにより、多角形を描いたときに線は黒で描かれ、線が重なる部分は白になります。(白い線を重ねて描けば重なる部分が反転すると考えても良いと思います。)
更にstrokeCap()によって線端を変えることで、多角形の頂点で線が重なる部分に変化が出せます。strokeCap()の特徴は既に説明している通りで、線端の形や線の長さが変わります。
blendMode(DIFFERENCE)とstrokeCap()を使うことで、線の重なる部分に変化を加えることができ、描画のバリエーションが豊かな表現を生み出します。
作例
上で用意したline()で多角形を描く関数line_polygon()。blendMode(DIFFERENCE)とstrokeCap()の組み合わせ。これらを作品に適用していきます。
多角形を左右上下に並べ、それぞれの描画時に頂点数や大きさ、線幅をランダムに選択する作例です。次のコードになります。
function setup() {
createCanvas(600, 600);
background(255);
stroke(255);
noLoop();
}
function draw(){
blendMode(DIFFERENCE);
for(let i=0;i<=width;i+=width/8){
for(let j=0;j<=height;j+=height/8){
strokeWeight( int(random(8,32)) );
strokeCap( random([ROUND, SQUARE, PROJECT]) );
line_polygon(i, j, int(random(20,40)), int(random(3,16)));
}
}
}
function line_polygon(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);
for(let i=0;i<point_num;i++){
line(cx[i], cy[i], cx[(i+1)%point_num], cy[(i+1)%point_num]);
}
pop();
}
ここまでで既に何度も見ていますが、下の様になります。
for文を二重に使うことで、左右上下に均等に多角形を並べて描きます。
strokeWeight( int(random(8,32)) )で線幅をランダムに選択しています。重なる部分によって表現バリエーションが作られるので、線幅は大きめの値にして重なりがわかりやすいようにしています。
多角形の大きさはint(random(20,40))でランダムに選択します。大きすぎれば隣と重なりますし、小さすぎると点になってしまうので、程々の値にしています。
多角形の頂点数はrandom(3,16)で決めています。頂点数は大きくすれば重なる部分が多くなるのでより複雑な絵を描いてくれます。ここでは頂点数の少ない多角形の出現率などを考慮してこの値にしてみました。
おわりに
line()の魅力を引き出すために、line()の性質を改めて学んでみました。
その特徴を使って、blendMode(DIFFERENCE)とstrokeCap()の組み合わせを用いて多角形を描くことで、line()だけを使ったジェネラティブ・アートを作成しました。
line()だけでも十分に表情豊かな作品を作れると思います。皆さんもline()の魅力を引き出して遊んでみてください。
続きの記事を書いています。
余談
紹介したジェネラティブ・アートをtwitterに投稿したところ、思った以上に反響がありました。嬉しいですね。
灯台下暗しということでしょうか。シンプルだけど見落としていることが、まだまだあるかもしれないですね。
ちなみに、色をつけるとこんな雰囲気になりました。
この記事が気に入ったらサポートをしてみませんか?