歯車のフラクタル for p5.js


2018年02月10日
With
歯車のフラクタル for p5.js はコメントを受け付けていません

このところWebGLモードが気になってそっちばっかりいじってたんですが、今回は久しぶりに、こちらの本に出ていたProcessingスケッチのp5.js版を。


■ [普及版]ジェネラティブ・アート―Processingによる実践ガイド

僕がクリエイティブコーディングにハマるきっかけを作ってくれたこの本では、最終章「フラクタル」のサンプルとして「歯車のフラクタル(cog fractals)」「サトクリフの五角形(Sutcliffe pentagons)」の2つのProcessingスケッチが紹介されています。いずれもフラクタルの要件である再帰の仕組みを持ち、造形の美しさや飽きさせない動きも兼ね備えたすてきなスケッチです。

このあたりをp5.js向けに書き直しながら写経していたのは、もう8カ月くらい前のことになるんですね。当初はES5で機械的にコードを置き換え、とりあえず走らせてみて、エラーが出たところをひとつずつ、原因を探り探りツブしていくということをやっていました。オブジェクトの書き方や、多次元配列の扱い方が分からず悶絶したのも懐かしい思い出です(トオイメ)。

今回、こちらにアップするにあたって、コードはES2015準拠にしてみました。

歯車のフラクタル

1つの点から「子」となる枝を何本か伸ばし、さらにその枝の先から「孫」「ひ孫」の枝が伸びていくというシンプルなフラクタルですが、各点がグルグルと回転することで、何となく生き物っぽい、有機的な印象のあるアニメーションが生成されます。

●歯車のフラクタル powered by p5.js(クリックすると別タブが開きます)

フラクタル系はどうしても処理が重くなりますね。このスケッチでも「子の数」と「世代数」の組み合わせをいろいろ試しながら、僕のPC環境のChromeで動きがコマ送りにならないあたりの数値にしてみました。子の数(_numChildren)を「7」、世代数(_maxLevels)を「4」(点の数は7の4乗+1の「2402」)としていますが、いろいろ変えて動かしてみると面白いと思います。

コードはこちら。

const _numChildren = 7;
const _maxLevels = 4;
let _trunk = [];
function setup() {
    createCanvas(600, 600);
    background(255);
    noFill();
    newTree();
}
function newTree() {
    _trunk = new Branch(1, 0, width / 2, height / 2);
    _trunk.drawMe();
}
function draw() {
    background(255);
    _trunk.updateMe(width / 2, height / 2);
    _trunk.drawMe();
}
class Branch {
    constructor(lev, ind, ex, why) {
        this.level = lev;
        this.index = ind;
        this.children = [];
        this.strokeW = (1 / this.level) * 10;
        this.alph = 1 / this.level;
        this.len = (1 / this.level) * random(500);
        this.rot = random(360);
        this.lenChange = random(10) - 5;
        this.rotChange = random(10) - 5;
        if (this.level <= _maxLevels) {
            for (let i = 0; i < _numChildren; i++) {
                this.children[i] = new Branch(this.level + 1, this.x, this.endx, this.endy);
            }
        }
    }
    updateMe(ex, why) {
        this.x = ex;
        this.y = why;
        this.rot += this.rotChange;
        if (this.rot > 360) { this.rot = 0; }
        else if (this.rot < 0) { this.rot = 360; }
        this.len -= this.lenChange;
        if (this.len < 0) { this.lenChange *= -1; }
        else if (this.len > 500) { this.lenChange *= -1; }
        var radian = radians(this.rot);
        this.endx = this.x + (this.len * cos(radian));
        this.endy = this.y + (this.len * sin(radian));
        this.children.forEach(allChild => { allChild.updateMe(this.endx, this.endy); });
    }
    drawMe(ex, why) {
        if (this.level > 1) {
            strokeWeight(this.strokeW);
            stroke('rgba(0,0,0,' + this.alph + ')');
            fill('rgba(255,255,255,' + this.alph + ')');
            line(this.x, this.y, this.endx, this.endy);
            ellipse(this.endx, this.endy, this.len / 12, this.len / 12);
        }
        this.children.forEach(allChild => { allChild.drawMe(); });
    }
}

次回は「サトクリフの五角形」です。