
noise๋ ์ก์, ์์น ์๋ ์ ํธ๋ ๋ถ๊ท์นํ ํจํด์ ๋ปํฉ๋๋ค.
์ผ๋ฐ์ ์ธ ๋
ธ์ด์ฆ๋ ์ฐ์์ ์ด์ง ์๊ณ ๊ธ๊ฒฉํ ๋ณํ๋ฅผ ๋ณด์ฌ์ค๋๋ค. ๊ทธ๋ฐ๋ฐ Ken Perlin์ด ๊ฐ๋ฐํ ํ๋ฆฐ ๋
ธ์ด์ฆ(Perlin Noise)๋ ๋ถ๋๋ฝ๊ณ ์์ฐ์ค๋ฌ์ด ํจํด์ ์์ฑํ๋ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ์์ฐ ํ์์์ ๋ณด์ด๋ ์ ๊ธฐ์ ์ธ ํจํด์ ๋ง๋ค ๋ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
Perlin noise ์ํคํผ๋์ ๋งํฌ
๋์ฒด๋ก Generative Art์์ ์ฌ์ฉํ๋ Noise๋ ์ฐ์์ฑ ์๋ ๋ฌด์์(continuous randomness)์
๋๋ค. ์ฆ, ์์ ํ ๋๋ค์ด์ง๋ง ์ธ์ ํ ๊ฐ๋ผ๋ฆฌ ๋ถ๋๋ฝ๊ฒ ์ฐ๊ฒฐ๋์ด ์๋ ๊ฒ์ด์ง์.
์ด๊ฑธ ์ด์ฉํด์ ์์ฐ ํ์์ด๋ ํ
์ค์ฒ, ์งํ, ํ๋ฆ, ์ ๊ธฐ์ ํํ๋ฅผ ํํํ ๋ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
Perlin Noise์ ํจ๊ป ์ ์ฐ์ด๋ ๋ ธ์ด์ฆ๋ ๋ง์ฐฌ๊ฐ์ง๋ก Perlin์ด 2001๋ ์ ๊ฐ๋ฐํ Simplex Noise์ ๋๋ค. ์ด ๋ ธ์ด์ฆ ์๊ณ ๋ฆฌ์ฆ์ "๊ณ ์ ์ "์ธ ํ๋ฆฐ ๋ ธ์ด์ฆ์ ์ ์ฌํ์ง๋ง ํจ์จ์ฑ์ด ๊ฐ์ ๋์๋ค๊ณ ํฉ๋๋ค.
์๋๋ ๋ช๊ฐ์ง ๋ ธ์ด์ฆ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
| Noise ์ข ๋ฅ | ํน์ง | p5.js ์ง์ ์ฌ๋ถ |
|---|---|---|
| Perlin Noise | ๋ถ๋๋ฝ๊ณ ๊ทธ๋ผ๋์ธํธ ๊ธฐ๋ฐ. ์์ฐ์ค๋ฌ์ด ์ฐ์์ฑ. | โ
๋ด์ฅ (noise()) |
| Simplex Noise | Perlin์ ๊ฐ์ ๋ฒ์ . ๊ณ ์ฐจ์์์ ๊ณ์ฐ์ด ๋น ๋ฅด๊ณ artifacts ์ ์. | โ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ |
| OpenSimplex Noise | Simplex ํนํ ๋ฌธ์ ๋ฅผ ํผํ ์คํ ๋ฒ์ . | โ ์ธ๋ถ ์ฝ๋ ํ์ |
| Worley Noise (Cellular Noise) | ์ ๊ตฌ์กฐ ๊ธฐ๋ฐ ํจํด (์: ์์, ํผ๋ถ ํ ์ค์ฒ ๋ฑ) | โ ์ธ๋ถ ์ฝ๋ ํ์ |
| Value Noise | ๊ฒฉ์์ ์ ๋๋ค๊ฐ์ ๋ณด๊ฐํ ์ด๊ธฐ ํํ์ noise | โ ์ง์ ๊ตฌํ ๊ฐ๋ฅ |

ํ๋ฆฐ ๋
ธ์ด์ฆ์ ๊ธฐ๋ณธ์ ์ธ 1์ฐจ์ ๋ผ์ธ์ผ๋ก ํํํ ์์์
๋๋ค.
์ผ์ชฝ์์ ์ค๋ฅธ์ชฝ์ผ๋ก ๋ถ๋๋ฝ๊ฒ ๋
ธ์ด์ฆ ๋ผ์ธ์ด ์๊ฒจ๋ฉ๋๋ค.
let xoff = 0;
function setup() {
createCanvas(800, 400);
background(255);
frameRate(60);
}
function draw() {
let y = noise(xoff) * height;
noStroke();
fill(0, 100);
// x ์์น: frameCount % width (์คํฌ๋กค์ฒ๋ผ ํ์)
ellipse((frameCount - 1) % width, y, 8, 8);
xoff += 0.02;
if (frameCount > width) {
noLoop();
}
}
๋ค๋ฅธ ๋๋์ ์ ๋๋ฉ์ด์
์ผ๋ก ์ฝ๋๋ฅผ ์งค ์๋ ์์ต๋๋ค.
์ฌ์ ๋๊ธฐ์ ๊ทธ๋ํ์ฒ๋ผ ํ๋ฅด๋ ๋ฏํ ์ ๋๋ฉ์ด์
์ ํํํ์ต๋๋ค.
let start = 0;
function setup() {
createCanvas(800, 400);
frameRate(60);
}
function draw() {
background(25);
noFill();
stroke(10, 190, 180);
strokeWeight(5);
beginShape();
let xoff = start;
for (let x = 0; x < width; x++) {
let y = noise(xoff) * height;
vertex(x, y);
xoff += 0.01;
}
endShape();
start += 0.01;
}

let scale = 0.02;
function setup() {
createCanvas(800, 400);
pixelDensity(1); // โ
ํฝ์
๋ฐ๋ 1๋ก ์ค์
noLoop();
}
function draw() {
background(25);
loadPixels();
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
let n = noise(x * scale, y * scale);
let bright = map(n, 0, 1, 0, 255);
// let bright = floor(n * 255);
let idx = (x + y * width) * 4;
pixels[idx] = bright;
pixels[idx + 1] = bright;
pixels[idx + 2] = bright;
pixels[idx + 3] = 255;
}
}
updatePixels();
}

์ ์์ ํ๋ฆ์ ๋ ธ์ด์ฆ ํ๋๋ก ํํํ๋ฉด ์ด๋ ๊ฒ ๋ฉ๋๋ค.
let inc = 0.1;
let scl = 10;
let cols, rows;
let zoff = 0;
let particles = [];
let flowfield = [];
function setup() {
createCanvas(800, 400);
cols = floor(width / scl);
rows = floor(height / scl);
flowfield = new Array(cols * rows);
for (let i = 0; i < 2000; i++) {
particles.push(new Particle());
}
background(25);
frameRate(60);
}
function draw() {
// build flow field
let yoff = 0;
for (let y = 0; y < rows; y++) {
let xoff = 0;
for (let x = 0; x < cols; x++) {
let angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
let v = p5.Vector.fromAngle(angle);
v.setMag(0.1);
let index = x + y * cols;
flowfield[index] = v;
xoff += inc;
}
yoff += inc;
}
zoff += 0.003;
// update particles
for (let p of particles) {
p.follow(flowfield);
p.update();
p.edges();
p.show();
}
}
// Particle class with safe follow (clamp indices)
class Particle {
constructor() {
this.pos = createVector(random(width), random(height));
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.maxSpeed = 2;
this.prev = this.pos.copy();
}
follow(vectors) {
let x = floor(this.pos.x / scl);
let y = floor(this.pos.y / scl);
// ์์ ํ๊ฒ ๋ฒ์ ํด๋จํ
x = constrain(x, 0, cols - 1);
y = constrain(y, 0, rows - 1);
let index = x + y * cols;
let force = vectors[index];
if (force) {
this.applyForce(force);
}
}
applyForce(force) {
// ๋ณต์ฌํด์ ์ ์ฉ (์๋ณธ ๋ฒกํฐ๋ฅผ mutate ํ์ง ์์)
let f = force.copy();
this.acc.add(f);
}
update() {
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
this.pos.add(this.vel);
this.acc.mult(0);
}
show() {
stroke(30, 210, 200, 10);
line(this.pos.x, this.pos.y, this.prev.x, this.prev.y);
this.updatePrev();
}
updatePrev() {
this.prev.x = this.pos.x;
this.prev.y = this.pos.y;
}
edges() {
if (this.pos.x > width) {
this.pos.x = 0;
this.updatePrev();
}
if (this.pos.x < 0) {
this.pos.x = width;
this.updatePrev();
}
if (this.pos.y > height) {
this.pos.y = 0;
this.updatePrev();
}
if (this.pos.y < 0) {
this.pos.y = height;
this.updatePrev();
}
}
}
๐ง ์ฐธ๊ณ
Retina ํ๋ฉด์์๋ pixelDensity() ๊ธฐ๋ณธ๊ฐ์ด 2์ด๋ฏ๋ก
loadPixels() ์ ์ค์ pixels[] ๋ฐฐ์ด ํฌ๊ธฐ๊ฐ width pixelDensity() height pixelDensity() 4๊ฐ ๋ฉ๋๋ค.
์ง์ ํฝ์
๋ฐฐ์ด์ ์กฐ์ํ ๋๋ ํญ์ pixelDensity(1)์ ๋ฃ๋ ๊ฒ์ด ์์ ํฉ๋๋ค.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sketch</title>
<link rel="stylesheet" type="text/css" href="/style.css">
<script src="/libraries/p5.min.js"></script>
<script src="/libraries/p5.sound.min.js"></script>
</head>
<body>
<!-- ES6 ๋ชจ๋ ๋ฐฉ์ ์ฌ์ฉ -->
<script type="module" src="simplex_noise_basic.js"></script>
</body>
</html>
// simplex_noise_basic.js
// ES6 ๋ชจ๋ ๋ฐฉ์ ์ฌ์ฉ
import { createNoise3D } from "https://unpkg.com/simplex-noise@4.0.1/dist/esm/simplex-noise.js";
let noise3D;
let time = 0;
function setup() {
createCanvas(800, 400);
noise3D = createNoise3D();
pixelDensity(1);
noStroke();
}
function draw() {
background(0);
// ํฝ์
๊ฐ๊ฒฉ์ ๋์์ ๊ณ์ฐ๋ ์ค์ด๊ธฐ
let step = 5;
for (let x = 0; x < width; x += step) {
for (let y = 0; y < height; y += step) {
let noiseVal = noise3D(x * 0.005, y * 0.005, time);
let brightness = map(noiseVal, -1, 1, 0, 255);
fill(brightness);
rect(x, y, step, step);
}
}
time += 0.01;
// fps ํ์
fill(255);
text(floor(frameRate()), 10, 20);
}
window.setup = setup;
window.draw = draw;

let points = [];
function setup() {
createCanvas(800, 400);
// ๋๋ค ํน์ง์ ์์ฑ
for (let i = 0; i < 50; i++) {
points.push(createVector(random(width), random(height)));
}
}
function worleyNoise(x, y) {
let minDist = Infinity;
for (let point of points) {
let distance = dist(x, y, point.x, point.y);
minDist = min(minDist, distance);
}
return minDist;
}
function draw() {
for (let x = 0; x < width; x += 2) {
for (let y = 0; y < height; y += 2) {
let value = worleyNoise(x, y);
let color = map(value, 0, 100, 255, 0);
fill(color);
noStroke();
rect(x, y, 2, 2);
}
}
noLoop();
}