
ํ์ฐ ์ ํ ์์ง์ โ๋ฌด์์๋ก ์์ง์ด๋ ์ ์๋ค์ด ์๋ก ๋ง๋๋ฉด์ ๋ญ์ณ์ง๋ ํจํดโ์ ๋ง๋๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๋์ก์ด, ๋ฒ๊ฐ, ๋๋ญ๊ฐ์ง, ํ๊ด, ๊ด๋ฌผ ๊ฒฐ์ ๋ฑ ์์ฐ์ ๋ถ๊ธฐ ๊ตฌ์กฐ(fractal branching)๋ฅผ ์ค๋ช ํ๋ ๋ํ์ ์ธ ์๋ฆฌ์ ๋๋ค.
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ์ด๋ฆ | Diffusion-Limited Aggregation (DLA) |
| ์๋ฏธ | ํ์ฐ(diffusion)์ ํ๋ ์ ์๋ค์ด ์๋ก ๋ฌ๋ผ๋ถ์ผ๋ฉฐ ์ฑ์ฅํ๋ ์งํฉ(aggregation)์ ํ์ฑ |
| ํต์ฌ ์์ด๋์ด | ์ ์๋ค์ด ๋ธ๋ผ์ด ์ด๋(๋ฌด์์ ๋ณดํ)์ ํ๋ค๊ฐ โํต(seed)โ์ ๋ฟ์ผ๋ฉด ๋ถ๋๋ค |
| ๊ฒฐ๊ณผ ํจํด | ๊ฐ์ง ๋ชจ์์ ํ๋ํ ๊ตฌ์กฐ (branching fractal) |
| ๊ด๋ จ ํ์ | ๋ ๊ฒฐ์ , ๋ฒ๊ฐ ๋ฐฉ์ , ์ ๊ธฐ ๋๊ธ, ์นจ์ , ์๋ฌผ ๋ฟ๋ฆฌ, ๊ท ์ฌ์ฒด ๋ฑ |
์๋(seed) ์
์ ํ๋๋ฅผ ์ค์ฌ์ ๋
โ ๋๋ฌด์ ๋ฟ๋ฆฌ๋ ๋ ๊ฒฐ์ ์ ์ค์ฌ ๊ฐ์ ์ญํ
์๋ก์ด ์ ์๋ฅผ ํ๋ฉด์ ์ธ๊ณฝ์ ๋ฌด์์๋ก ์์ฑ
๊ทธ ์
์๊ฐ ๋๋ค ์ํฌ(Random Walk) ํ๋ฉฐ ์ด๋
(์ํ์ข์ฐ, ํน์ ๋๊ฐ ํฌํจ ๋ฌด์์ ๋ฐฉํฅ์ผ๋ก ํ ์นธ์ฉ)
๋ง์ฝ ์
์๊ฐ ์ด๋ฏธ ๋ถ์ด์๋ ๊ตฌ์กฐ์ ์ ์ดํ๋ฉด
โ ๊ทธ ์๋ฆฌ์์ ๋ฉ์ถ๊ณ ๊ตฌ์กฐ์ ํก์(attach) ๋จ
๊ทธ๋ค์ ์๋ก์ด ์
์๋ฅผ ์์ฑํด์ ๊ฐ์ ๊ณผ์ ์ ๋ฐ๋ณต
โ ๊ฐ์ง์ฒ๋ผ ํ์ฅ๋์ด ์๋ผ๋จ
โ๏ธ ๋ ๊ฒฐ์ : ์ค์ฌ์์ ๊ฐ์ง๊ฐ ๋ป์ผ๋ฉฐ ๋ถ๊ธฐ
โก๏ธ ๋ฒ๊ฐ: ์ ๋ฅ๊ฐ ๊ฐ์ฅ ์งง์ ๊ธธ์ ๋ฐ๋ผ ํ์ฐ์ ์ผ๋ก ์ฑ์ฅ
๐ฟ ๋๋ฌด: ์๋์ง ํ๋ฆ์ ๋ฐ๋ผ ๋น๋์นญ์ ์ธ ๋ถ๊ธฐ ๊ตฌ์กฐ ํ์ฑ
๐ชจ ๊ด๋ฌผ ๊ฒฐ์ : ์ด์จ๋ค์ด ํ์ฐ๋๋ฉฐ ํ๋ฉด์ ๋ฌ๋ผ๋ถ์ด ์ฑ์ฅ
| ์ฃผ์ | ๊ด๊ณ |
|---|---|
| ๋๋ค(Randomness) | ์ ์ ์ด๋์ ๊ธฐ๋ฐ (๋ธ๋ผ์ด ์ด๋) |
| ๋ ธ์ด์ฆ(Noise) | ํ์ฐ ๊ฒฝ๋ก์ ์ฐ์์ ๋ณํ |
| ์์คํ (Systems) | ์ง๋จ์ ํ๋์ผ๋ก ๋ณต์ก์ฑ ์์ฑ |
| ํํ & ๊ตฌ์กฐ(Form & Structure) | ๋จ์ ๊ท์น โ ๋ณต์กํ ํ๋ํ ๊ตฌ์กฐ |

let walkers = [];
function setup() {
createCanvas(800, 400);
for (let i = 0; i < 400; i++) {
walkers.push(createVector(width / 2, height / 2));
}
background(15);
stroke(30, 240, 210, 20);
}
function draw() {
for (let w of walkers) {
point(w.x, w.y);
w.x += random(-2, 2);
w.y += random(-2, 2);
// ๊ฒฝ๊ณ ์ฒ๋ฆฌ: ์บ๋ฒ์ค ์์ ๊ฐ๋๊ธฐ (Constrain)
w.x = constrain(w.x, 0, width);
w.y = constrain(w.y, 0, height);
}
}


const MAX_PARTICLES = 1000; // ๋์์ ์กด์ฌํ๋ ์
์ ์
const STICKINESS = 5; // ์์ง ๊ฑฐ๋ฆฌ
const WALK_STEP = 2; // ๋๋ค ์ํฌ ํ ๋ฒ์ ์ด๋ํ๋ ๊ฑฐ๋ฆฌ
const MAX_WALK_COUNT = 5; // ์
์๋น ํ๋ ์๋น ๋๋ค ์ํฌ ํ์
let particles = [];
let stuck = [];
let maxRadius = 0;
function setup() {
createCanvas(800, 400);
background(15);
colorMode(RGB, 255);
// ์ด๊ธฐ ์๋ ์์ฑ
stuck.push(createVector(width / 2, height / 2));
maxRadius = 1;
}
function draw() {
background(15, 15, 15, 20);
// 1. ์
์ ์์ฑ: ํจํด ์ธ๊ณฝ์์ ์์ฑ
if (particles.length < MAX_PARTICLES) {
let launchRadius = maxRadius + 50;
let angle = random(TWO_PI);
let x = width / 2 + cos(angle) * launchRadius;
let y = height / 2 + sin(angle) * launchRadius;
particles.push(createVector(x, y));
}
// 2. ์
์ ์ด๋ ๋ฐ ์์ง ํ์ธ
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
// ๐ ๊ฐ์ํ 1: ์
์๋น ์ฌ๋ฌ ๋ฒ์ ๋๋ค ์ํฌ ์ํ (์๋ ์ฆํญ)
for (let k = 0; k < MAX_WALK_COUNT; k++) {
p.x += random(-WALK_STEP, WALK_STEP);
p.y += random(-WALK_STEP, WALK_STEP);
}
let closestDistSq = Infinity;
// ๐ ๊ฐ์ํ 2: ํจํด ์ธ๊ณฝ์ ์ ๊ทผํ์ ๋๋ง ์ถฉ๋ ํ์ธ
let distFromCenter = dist(width / 2, height / 2, p.x, p.y);
if (distFromCenter < maxRadius + STICKINESS * 2) {
// ์
์๊ฐ ์์ง์ฒด ๊ทผ์ฒ์ ๋๋ฌํ์ ๋๋ง N*M ์ถฉ๋ ๊ฒ์ฌ ์คํ
for (let s of stuck) {
let dSq = (p.x - s.x) ** 2 + (p.y - s.y) ** 2;
closestDistSq = min(closestDistSq, dSq);
}
// ์์ง ์กฐ๊ฑด
if (closestDistSq < STICKINESS * STICKINESS) {
stuck.push(p);
particles.splice(i, 1);
// ์ต๋ ๋ฐ์ง๋ฆ ์
๋ฐ์ดํธ
if (distFromCenter > maxRadius) {
maxRadius = distFromCenter;
}
break; // ์์ง ํ ๋ค์ ์
์๋ก
}
}
// ๐ ๊ฐ์ํ 3: ๋๋ฌด ๋ฉ๋ฆฌ ๋๊ฐ ์
์ ์ ๊ฑฐ (์ต๋ ๋ฐ์ง๋ฆ + 1000 ์ด์)
// ํจํด์ด ์ปค์ง ๋ ํจ์จ์ ์ผ๋ก ์
์๋ฅผ ์ ๊ฑฐํ๋๋ก ๋ฒ์ ํ์ฅ
if (distFromCenter > maxRadius + 1000) {
particles.splice(i, 1);
}
}
// 3. ๋๋ก์
noStroke();
fill(255);
for (let s of stuck) circle(s.x, s.y, 3);
fill(30, 190, 180);
for (let p of particles) circle(p.x, p.y, 3);
}


const MAX_PARTICLES = 1000;
let particles = [];
let stuck = [];
function setup() {
createCanvas(800, 600);
background(15);
// ์ค์ฌ seed
stuck.push(createVector(width / 2, height / 2));
}
function draw() {
fill(15, 15, 15, 30);
rect(0, 0, width, height);
// ์๋ก์ด ์
์ ์์ฑ (๋ฌด์์ ๊ฐ์ฅ์๋ฆฌ)
if (frameCount % 1 === 0) { // ๋งค ํ๋ ์๋ง๋ค ์
์ ์์ฑ
let angle = random(TWO_PI);
let r = width / 2 - 10;
let x = width / 2 + cos(angle) * r;
let y = height / 2 + sin(angle) * r;
particles.push(createVector(x, y));
}
// MAX_PARTICLES ๊ฐ์๋ณด๋ค ์ ์ ๋๋ง ์๋ก์ด ์
์๋ฅผ ์์ฑํฉ๋๋ค.
if (particles.length < MAX_PARTICLES) {
if (frameCount % 2 === 0) {
// ... ๊ธฐ์กด ์
์ ์์ฑ ์ฝ๋ ...
let angle = random(TWO_PI);
let r = width / 2 - 10;
let x = width / 2 + cos(angle) * r;
let y = height / 2 + sin(angle) * r;
particles.push(createVector(x, y));
}
}
// ์
์ ์ด๋
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += random(-3, 3);
p.y += random(-3, 3);
// ์ค์ฌ ์ชฝ์ผ๋ก ์ด๋
let center = createVector(width / 2, height / 2);
let dir = p5.Vector.sub(center, p).setMag(0.5);
p.add(dir);
// ๋ถ๊ธฐ ๊ฒ์ฌ
for (let s of stuck) {
if (p.dist(s) < 3) {
stuck.push(p);
particles.splice(i, 1);
break;
}
}
// ํ๋ฉด ๋ฐ ์ ๊ฑฐ
if (p.x < 0 || p.x > width || p.y < 0 || p.y > height) {
particles.splice(i, 1);
}
}
// ๊ทธ๋ฆฌ๊ธฐ
noStroke();
fill(255);
for (let s of stuck) circle(s.x, s.y, 3);
fill(30, 190, 180);
for (let p of particles) circle(p.x, p.y, 2);
}

let particles = [];
let stuck = [];
let colors = [];
function setup() {
createCanvas(600, 600);
background(0);
colorMode(HSB);
noStroke();
// ์ค์ฌ seed
stuck.push(createVector(width / 2, height / 2));
colors.push(0); // generation 0
}
function draw() {
// ์ผ์ ๊ฐ๊ฒฉ์ผ๋ก ์
์ ์ถ๊ฐ
if (frameCount % 1 === 0) {
let angle = random(TWO_PI);
let r = width / 2 - 5;
let x = width / 2 + cos(angle) * r;
let y = height / 2 + sin(angle) * r;
particles.push(createVector(x, y));
}
// ์
์ ์ด๋ ๋ฐ ๋ถ๊ธฐ ๊ฒ์ฌ
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += random(-2, 2);
p.y += random(-2, 2);
// ํ๋ฉด ์ค์์ผ๋ก ํฅํ๋ ์ฝํ ํ
let center = createVector(width / 2, height / 2);
let dir = p5.Vector.sub(center, p).setMag(0.2);
p.add(dir);
for (let j = 0; j < stuck.length; j++) {
let s = stuck[j];
if (p.dist(s) < 3) {
stuck.push(p);
colors.push(colors[j] + 1);
particles.splice(i, 1);
break;
}
}
// ํ๋ฉด ๋ฐ์ผ๋ก ๋๊ฐ๋ฉด ์ ๊ฑฐ
if (p.x < 0 || p.x > width || p.y < 0 || p.y > height) {
particles.splice(i, 1);
}
}
// ๋ถ์ ์
์ ๊ทธ๋ฆฌ๊ธฐ
for (let i = 0; i < stuck.length; i++) {
let hue = map(colors[i], 0, 80, 0, 360) % 360;
fill(hue, 255, 255);
circle(stuck[i].x, stuck[i].y, 3);
}
// ๋ชจ์ฌ๋๋ ์
์
fill(30, 30 ,30);
for (let p of particles) {
circle(p.x, p.y, 2);
}
// ์ฑ์ฅ ์ ํ (ํ๋ฉด์ด ๊ฐ๋ ์ฐผ์ ๋ ์ ์ง)
if (stuck.length > 2000) {
noLoop();
console.log("DLA growth complete!");
}
}

DLA๋ฅผ ์ํํ๋ ํํฐํด์ ์ค๋ ฅ๊ณผ ๋ฐ๋์ ์ํฅ์ ์๋ฎฌ๋ ์ด์
ํ ์ ์์ต๋๋ค. ๋๋ค์ํฌ๋ฅผ ํ๋ ์์ค์๋ x, y ์ขํ๋ฅผ ๋งค ํ๋ ์๋ง๋ค ๋ฐฉํฅ์ฑ์ด ์๊ฒ ์์น๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ์ํ๋ ๋ฐฉํฅ๊ณผ ์๋๋ก ์์ง์ด๋ฉด์ ์์ง์ ํ๊ฒ ํฉ๋๋ค. ์๋ ์ฝ๋๋ ๋ง์น ๋์ด ์์ด๋ ๋ฏํ ๋ชจ์ต์ ์ฐ์ถํ๊ณ ์์ต๋๋ค.
const MAX_PARTICLES = 300;
const STICKINESS = 5;
let particles = [];
let stuck = [];
function setup() {
createCanvas(800, 400);
background(15);
colorMode(RGB, 255);
// ๋ฐ๋ฅ๋ฉด ์ ์ฒด๋ฅผ ์๋๋ก ์ค์
let seedSpacing = 3; // ์๋ ๊ฐ๊ฒฉ (๊ฐ๊ฒฉ์ด ์ข์์๋ก ์์ง์ด ๋น ๋ฅด๊ณ ๋ถ๋๋ฌ์)
for (let x = 0; x <= width; x += seedSpacing) {
// ์บ๋ฒ์ค ์๋ซ๋ฉด(y = height - 1)์ ์๋๋ฅผ ๋ฐฐ์นํฉ๋๋ค.
stuck.push(createVector(x, height - 1));
}
}
function draw() {
// ๋ฐฐ๊ฒฝ์ ํฌ๋ช
ํ๊ฒ ๋ฎ์ด ์น ํ์ฌ ๊ถค์ ์์ ํจ๊ณผ ์์ฑ
fill(15, 15, 15, 50);
rect(0, 0, width, height);
// ์๋ก์ด ์
์ ์์ฑ (์์ชฝ์์ ๋จ์ด์ง)
if (particles.length < MAX_PARTICLES) {
if (frameCount % 1 === 0) {
let x = random(width);
let y = 0; // ์บ๋ฒ์ค ์๋จ
particles.push(createVector(x, y));
}
}
// ์
์ ์ด๋ ๋ฐ ์์ง (์์) ๊ฒ์ฌ
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
// ์
์ ์ด๋: ์ค๋ ฅ(Y)๊ณผ ๋ฐ๋(X)
p.x += random(-1.5, 1.5); // x์ถ: ๋ฐ๋
p.y += random(3, 7); // y์ถ: ์ค๋ ฅ
// ๋ถ๊ธฐ(์์ง) ๊ฒ์ฌ
let isStuck = false;
for (let s of stuck) {
if (p.dist(s) < STICKINESS) {
stuck.push(p);
particles.splice(i, 1);
isStuck = true;
break;
}
}
if (isStuck) continue; // ๋ถ์์ผ๋ฉด ๋ค์ ์
์๋ก
// ํ๋ฉด ๋ฐ ์ ๊ฑฐ (๋ฐ๋ฅ์ ์ง๋์น ์
์ ์ ๊ฑฐ)
if (p.y > height + 10) particles.splice(i, 1);
}
// ๊ทธ๋ฆฌ๊ธฐ
noStroke();
// ์์ง๋ ์
์ (์์ธ ๋/๋ฐ๋ฅ)
fill(255, 200);
for (let s of stuck) circle(s.x, s.y, 10);
// ์์ง์ด๋ ์
์ (๋/ํํฐํด)
fill(255, 200);
for (let p of particles) circle(p.x, p.y, 10);
}