Mod:Coding Challenge #18: 3D Fractal Trees
フラクタルツリーの3D版。長かったけど、2Dのアルゴリズムが作れるとあとは次元を1つ増やして3Dにするだけとも言えるのでそれほど難度を感じなかった。ツリーっぽい形にしたかったのでLeafの生成のところの初期値を山形になるように変更した。
今頃台風来てるので驚く。気圧が低くなると頭が痛くなる気がする。コーヒーで血管広げてる。
import peasy.*; PeasyCam cam; Tree tree; float min_dist = 5; float max_dist = 500; void setup() { size(600, 900, P3D); cam = new PeasyCam(this, 500); colorMode(HSB, 360, 100, 100, 100); tree = new Tree(); } void draw() { background(0, 0, 33); tree.draw(); tree.grow(); } class Tree { ArrayList<Branch> branches = new ArrayList<Branch>(); ArrayList<Leaf> leaves = new ArrayList<Leaf>(); Tree() { for (int i = 0; i < 1000; i++) { leaves.add(new Leaf()); } Branch root = new Branch(new PVector(0, height/2, 0), new PVector(0, -1)); branches.add(root); Branch current = new Branch(root); while (!closeEnough(current)) { Branch trunk = new Branch(current); branches.add(trunk); current = trunk; } } boolean closeEnough(Branch b) { for (Leaf l : leaves) { float d = PVector.dist(b.pos, l.pos); if (d < max_dist) { return true; } } return false; } void grow() { for (Leaf l : leaves) { Branch closest = null; PVector closestDir = null; float record = -1; for (Branch b : branches) { PVector dir = PVector.sub(l.pos, b.pos); float d = dir.mag(); if (d < min_dist) { l.reached(); closest = null; break; } else if (d > max_dist) { } else if (closest == null || d < record) { closest = b; closestDir = dir; record = d; } } if (closest != null) { closestDir.normalize(); closest.dir.add(closestDir); closest.count++; } } for (int i = leaves.size()-1; i >= 0; i--) { if (leaves.get(i).reached) { leaves.remove(i); } } for (int i = branches.size()-1; i >= 0; i--) { Branch b = branches.get(i); if (b.count > 0) { b.dir.div(b.count); b.dir.normalize(); PVector rand = PVector.random3D(); rand.setMag(0.3); b.dir.add(rand); Branch newB = new Branch(b); branches.add(newB); b.reset(); } } } void draw() { for (Leaf l : leaves) { l.draw(); } for (int i = branches.size()-1; i >= 0; i--) { Branch b = branches.get(i); if (b.parent != null) { stroke(0, 0, 100); strokeJoin(PROJECT); float sw = map(i, 0, branches.size(), 5, 1); strokeWeight(sw); line(b.pos.x, b.pos.y, b.pos.z, b.parent.pos.x, b.parent.pos.y, b.parent.pos.z); } } } } class Branch { Branch parent; PVector pos; PVector dir; int count = 0; PVector saveDir; float len = 5; Branch(PVector _pos, PVector _dir) { parent = null; pos = _pos; dir = _dir; saveDir = dir; } Branch(Branch _parent) { parent = _parent; pos = parent.next(); dir = parent.dir; saveDir = dir; } void reset() { count = 0; dir = new PVector(saveDir.x, saveDir.y); } PVector next() { PVector v = PVector.mult(dir, len); PVector next = PVector.add(pos, v); return next; } } class Leaf { PVector pos; boolean reached = false; float d = 4; Leaf() { float y = (random(1) + random(1) + random(1)+ random(1)+random(1)) / 5; float x = random(map(y, 0, 1, 0, 0.35)); float z = random(map(y, 0, 1, 0, 0.35)); if (random(1) < 0.5) { x *= -1; } if (random(1) < 0.5) { z *= -1; } pos = new PVector(x, y, z); pos.mult(random(width/2)); pos.y -= height/4; } void reached() { reached = true; } void draw() { fill(0, 0, 100); noStroke(); pushMatrix(); translate(pos.x, pos.y, pos.z); ellipse(0, 0, d, d); popMatrix(); } }