xxxxxxxxxx
let currTree
let startTime = 0
function setup() {
createCanvas(windowWidth, windowHeight);
background(100);
currTree = Tree(width, height).start().growAll().sort()
}
function mouseClicked() {
currTree = Tree(width, height).start().growAll().sort()
startTime = millis()
}
function draw() {
background(0)
push()
currTree.render(millis() - startTime)
pop()
}
const Tree = (w, h) => {
const resolution = min(width, height) * 0.008;
const tree = {
elements: [],
spawnPoints: [],
start: () => {
const initial = [w*0.5, h*0.65, 0, 1];
const initialR = min(width, height) * 0.06;
tree.spawnPoints.push({
at: initial,
dir: [0, -1, 0, 0],
r: initialR,
scale: [0.9, 1.05],
children: [1, 0.01, 0.005],
depth: 0
});
const numRoots = round(random(3, 6));
for (let i = 0; i < numRoots; i++) {
const dir = [0, 1, 0, 0];
vec4.transformMat4(
dir,
dir,
mat4.fromRotation(
[], random(PI*0.2, PI*0.5), [0, 0, 1]));
vec4.transformMat4(
dir,
dir,
mat4.fromRotation(
[], random(0, PI*2), [0, 1, 0]));
tree.spawnPoints.push({
at: initial,
dir,
r: initialR,
scale: [0.7, 1.01],
children: [1, 0.005, 0.005],
depth: 0
});
}
return tree;
},
add: element => tree.elements.push(element),
extend: spawnPoint => {
const [x, y, z, _] = spawnPoint.at;
if (spawnPoint.r < 0.1) return;
tree.add({
x,
y,
z,
r: spawnPoint.r,
depth: spawnPoint.depth
});
spawnPoint.children.forEach(probability => {
if (random(0,1) > probability) return;
const normal = [
vec3.cross(
[],
spawnPoint.dir,
vec3.normalize([], [random(-1,1), random(-1,1), random(-1,1)])),
0
];
const nextLoc = vec4.add(
[],
spawnPoint.at,
vec4.scale([], spawnPoint.dir, resolution));
const nextDir = vec4.transformMat4(
[],
spawnPoint.dir,
mat4.fromRotation([], random(0, PI*0.2), normal));
vec4.transformMat4(
nextDir,
nextDir,
mat4.fromRotation([], random(0, PI*0.2), spawnPoint.dir));
const nextR = spawnPoint.r * random(spawnPoint.scale);
tree.spawnPoints.push({
at: nextLoc,
dir: nextDir,
r: nextR,
scale: spawnPoint.scale,
children: spawnPoint.children,
depth: spawnPoint.depth + 1
});
});
},
grow: () => {
const queue = tree.spawnPoints;
tree.spawnPoints = [];
queue.forEach(point => tree.extend(point));
return tree;
},
growAll: () => {
while (tree.spawnPoints.length > 0) {
tree.grow();
}
return tree;
},
renderElement: (element, t) => {
if (t > element.depth*50) {
const offX = 10*sin(t*0.0008 + element.depth*0.15)
const offY = 10*sin(t*0.00092 + element.depth*0.15)
circle(element.x+offX, element.y+offY, max(element.r * 2, 1) * map(t, element.depth*50, element.depth*50 + 1000, 0, 1, true))
}
},
sort: () => {
tree.elements
.sort((a, b) => a.z - b.z) // Painter's algorithm
return tree
},
render: (t) => {
tree.elements.forEach(element =>
tree.renderElement(element, t));
}
}
return tree
}