p5.jsからL-systemを用いてGenerative Artを作成
はじめに
Generative Artの一環として、今回はL-systemモデルを利用してオブジェクトを描画してみようと思います。 L-systemは植物の成長過程をモデル化を目的として開発されたものですが、 このモデルを利用して植物以外にも様々な疑似的な自然物を構築するためにも利用されています。
L-systemモデルは置換法則などの一定の文法法則に従って再帰的に実行されますが、この再帰過程が自然物の成長過程を表現しています。 この文法に従った再帰性によりフラクタル図形として生成されるので、 Generative Artといったアルゴリズム的なアートの生成手法の一つとしてL-systemが利用されています。
コードを実装するするにあたっては前回と同じくp5.jsを使用します。
L-system
L-systemの概要について説明します。
L-systemの文法モデルは
: 状態を表す文字列 : 初期の状態を表す文字列 : 変換時の文字列の置換法則(F -> F+F--F+F など)
L-systemでは状態は文字列で表現されますが、それぞれの文字列は描画時に何をするかを指示するものになっています(F: 線を描画して終端に移動、B: 線を描画せず移動する など)。 他にも以下のような定数文字が使用されます。 一般的以下のものは置換法則によって変換はされませんが、生成された記述文字列を描画実行する際に描画状態の変更を指示する記号として用いられます。
- +, - : 線の描画方向の変更する(+と-は方向を示す)
- [, ] : 描画状態をスタックにpush,popする(p5.jsでいうところのtranslateやrotate状態の保持)
[, ] 文字は分岐構造を作りたい時などに便利です。
L-systemの変換(成長)過程はstep数に対して指数関数的に文字列が増加しますので注意が必要です。
例えば変換法則が F -> F+F--F+F なら
コッホ曲線
コッホ曲線は自己相似図形を持つフラクタル図形の一種ですが、L-systemを使用して構築することができます。 構築したい図形の形は初期値や置換法則等を変えることで多様性を持たせることができます。その一つの例を作成してみようと思います。
使用するL-systemモデルは以下になります。
- 使用する文字 :
: : : 一定角度分の方向転換 : 線を描画
どのような図形になるかを想像しながら初期値や角度、置換法則を考えるとやりやすいです。 コッホ曲線などの自己相似図形を構築するときは+と-の数は等しくなるように置換法則を設定するとよいと思います。 以下はコッホ曲線の一種を構築するコードになります。draw関数が必要ない時はsetup関数にnoLoop()を付け加えてもいいです。
const outgif = false; const W = 1080; const H = 1080; const N = 6; let dangle; let dx = 9; let dy = 9; const colors = ["red", "orange", "yellow", "green", "cyan", "blue", "purple"]; const rules = { 'F': 'F+F--F+F', }; function setup() { createCanvas(W, H); background(0); frameRate(30); createLoop({duration:4, gif:outgif}); dangle = radians(85); let system = build_l_system('F'); let margin = 63; init_draw(system, margin, H-margin, 0); } function apply_once(s) { let ret = ''; for(let si of s) { if(rules[si]) { ret += rules[si]; } else { ret += si; } } return ret; } function build_l_system(s) { let result = s; for(let i = 0;i < N;++i) { result = apply_once(result); } return result; } function init_draw(s, sx, sy, a) { let x = sx; let y = sy; let angle = radians(a); let cid = 0; for(let si of s) { if(si == 'F') { let nx = x + dx*cos(angle); let ny = y - dy*sin(angle); stroke(colors[cid]); line(x, y, nx, ny); x = nx; y = ny; } else if (si == '+') { angle += dangle; cid = (cid+1)%7; } else if (si == '-') { angle -= dangle; cid = (cid+6)%7; } else { } } } function draw() { }
以下の画像では上記コードを少し工夫をして、複数の曲線を構築して配置しました。
フラクタル形状の木
次の例は植物のような形状を作成してみようと思います。 植物形状を構築する際に枝分かれが必要となるので、[,]文字を使用します。
- 使用する文字 :
: : : : 一定角度分の方向転換 : 線を描画(Xはskipでも可)
こちらではtranslateとrotate関数を積極的に使っていきます。 状態の保存にはpush関数とpop関数が便利です。
function init_draw(s, sx, sy, a, inia) { let cid = int(random(0,7)); push(); translate(sx, sy); rotate(inia); for(let si of s) { if(si == 'F') { stroke(colors[cid]); line(0, 0, 0, -dy); translate(0, -dy); } else if(si == 'X') { stroke(colors[cid]); line(0, 0, 0, -dy); translate(0, -dy); } else if(si == '[') { push(); } else if(si == ']') { pop(); } else if (si == '+') { rotate(a); cid = (cid+1)%7; } else if (si == '-') { rotate(-a); cid = (cid+6)%7; } else { } } pop(); }
以下の画像は複数の木を構築し、置換法則を適用する確率と角度にランダム要素を加えました。
その他のL-systemを利用した描画例
- 使用する文字 :
: : : 77°方向転換 : 線を描画
回転角は0-90度の範囲で設定し、+を連続で繰り返すことで線は逆方向に折り返されます。
- 使用する文字 :
: : : 90°方向転換 : 線を描画 : skip
正方形を階段状に並べたものです。
まとめ
L-systemのパターンは今回紹介したものだけではなく、まだまたたくさんあります。
自然物の描画モデルに関してはL-systemだけではなく、力学的なモデルなどまだ多様なモデルが存在します。 Generative Artに適用可能なモデルも多岐にわたっているようなので、 アート的な意味だけではなく計算機分野的な意味でも奥は深いかと思います。