「p5.jsでフラクタルイメージを描く」シリーズ。今回はWebGLモードを使って3Dで描いてみます。題材は「メンガーのスポンジ」です。
・メンガーのスポンジ - Wikipedia
・Menger sponge - Wikipedia(英語版、解説はこちらのほうが詳細)
これを描いてみようと思ったきっかけは、こちらのビデオ。
・Coding Challenge #2: Menger Sponge Fractal - The Coding Train
「The Coding Train」というYouTubeチャンネルには、主にProcessingとp5.jsを使ったクリエイティブ・コーディングのチュートリアルが大量にアップされています。やたらハイテンションなヒゲの講師はダニエル・シフマン先生といい、Processing界隈では大変有名な方です。日本語版も出ている「Nature of Code」という本の著者でもあります。僕も持ってます。
■ Nature of Code – Processingではじめる自然現象のシミュレーション
Coding Challengeシリーズは、いわゆる「10分で作る○○」的なヤツで、シフマン先生が毎回、終始ハイテンションでライブコーディングします。「メンガーのスポンジ」のビデオはProcessing向けなのですが、英語字幕を目で追いながら、p5.js向けに移植してみました。あ、今回はES2015準拠で書いています。
●メンガーのスポンジ powered by p5.js(クリックすると別タブが開きます)
開くと、画面一杯に立方体が回転しはじめます。ブラウザ上で1回クリックする度に、再帰が1段階進みます。ビデオに出てくるコードは、クリックすればするほど、どんどん再帰が深くなっていくものだったのですが、当然のごとく再帰が深くなればなるほど処理が重くなり、しまいにはほぼ完全な静止状態(処理待ち)になってしまいます。それを避けるために、こちらのプログラムでは、最深の再帰回数を3回とし、4回目にクリックしたら初期状態に戻るようにしました。環境によっては、3回再帰でも相当重くなるかと思われます。
あと今回は、試しに「p5.sound.js」を使って音を付けてみました。クリックしたときに「カチッ」と鳴るようになってます。今回のスケッチとは直接関係ないのですが、p5.sound.jsでBGMを流したい場合、AndroidとiOSとで、自動再生の処理が異なる(iOSの場合だけ?、一度何らかのユーザーイベントを取らないと再生が始まらない?)みたいですね。p5.jsでゲームっぽいものを作ろうと思うと、このあたりをどう回避、吸収するかも課題になりそうですねぇ。
今回のコードはこちらです。(要「p5.js」「p5.sound.js」)
let a = 0; let b; let sponge = new Array(); const recursiveLimit = 4; let recursiveCount = 0; let clickSe; function setup() { clickSe = loadSound('./assets/clickse.mp3'); createCanvas(600, 600, WEBGL); ambientLight(100); directionalLight(120, 120, 120, -1, -1, 1); ambientMaterial(230, 210, 255, 255); noStroke(); resetCube(); } function mousePressed() { clickSe.play(); ++recursiveCount; if (recursiveCount >= recursiveLimit) { resetCube(); return; } let next = new Array(); sponge.forEach(abox => { let newBoxes = abox.generate(); next = concat(next, newBoxes); }); sponge = next; } function draw() { camera(0, 0, 500, 0, 0, 0, 0, 1, 0); background(30, 30, 60); rotateX(a); rotateY(a * 0.4); rotateZ(a * 0.1); sponge.forEach(abox => { abox.show(); }); a += 0.01; } function resetCube() { b = new Box(0, 0, 0, 300); sponge = [b]; recursiveCount = 0; } class Box { constructor(x, y, z, r_) { this.pos = createVector(x, y, z); this.r = r_; } generate() { let boxes = new Array(); for (let x = -1; x < 2; x++) { for (let y = -1; y < 2; y++) { for (let z = -1; z < 2; z++) { let sum = abs(x) + abs(y) + abs(z); const newR = this.r / 3; if (sum > 1) { let b = new Box(this.pos.x + x * newR, this.pos.y + y * newR, this.pos.z + z * newR, newR); boxes.push(b); } } } } return boxes; } show() { push(); translate(this.pos.x, this.pos.y, this.pos.z); box(this.r); pop(); } }
さて、これまで何度かp5.jsのWebGLモードでスケッチしているのですが、最新のバージョンアップで一部機能変更があったりしているので、今回、メンガーのスポンジを描くにあたって、改めて基本的な使い方を復習してみました。そのあたりの簡単なまとめを含む3Dスケッチを追って作ってみます。
p5.jsのWebGLモードでなんとなく3Dフラクタル はコメントを受け付けていません