
๋๋ค์ด๋ ๋ฌด์์์ฑ, ๋น๊ฒฐ์ ์ฑ, ์์ธก๋ถ๊ฐ๋ฅ์ฑ์ ์๋ฏธํฉ๋๋ค.
์ฆ, "์ด๋ค ๊ท์น๋ ์์ด ํฉ์ด์ง๋ ๊ฐ"์ ์ด์ผ๊ธฐํ๋ ๊ฒ์ด์ง์. ์ฌ๋ฌ ๋ฐฉ์์ผ๋ก ๋ฌด์์์ ์ ์, ์ค์๋ฅผ ํน์ ๋ฒ์ ์์์ ์ถ์ถํ๊ณ ๊ทธ๊ฒ์ ์ํธ์ํฌ ์ ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ด๋ฒ ์ฑํฐ์ ์ฃผ์ ์ ๋๋ค.
p5.js์์๋ ์ด๋ฐ ํจ์๋ค๋ก ๋ฌด์์์ฑ์ ํํํฉ๋๋ค.()์์ ์ธ์๋ ํจ์๋ง๋ค ์ ํด์ ธ ์์ต๋๋ค.
random() โ ์์ ํ ๊ท ์ผ ๋ถํฌ (Uniform random)
randomGaussian() โ ์ ๊ท๋ถํฌ์ ๊ธฐ๋ฐ ๋ฌด์์ ๋ถํฌ
randomSeed() โ ๋๋ค ์๋ ๊ณ ์
shuffle(), randomChoice() โ ๋ฐฐ์ด์ ์๊ฑฐ๋ ์์๋ก ์ถ์ถ

function setup() {
createCanvas(800, 400);
background(16);
noLoop();
}
function draw() {
noStroke();
for (let i = 0; i < 3000; i++) {
fill(random(0, 255), random(0, 255), random(0, 255), random(70, 250));
let x_pos = random(width);
let y_pos= random(height);
ellipse(x_pos, y_pos, 7, 7);
}
}
- ์ด ์ฝ๋์์๋ ๋ชจ๋ ์ ์ด ๊ฐ์ ํ๋ฅ ๋ก ์บ๋ฒ์ค์ ๋ฐฐ์น๋ฉ๋๋ค.
- ๋ํ์ ์์ ์ฑ์ฐ๊ธฐ ์ํด
fill()์ ์ฌ์ฉํฉ๋๋ค.- fill() ํจ์์ ์ธ์ r,g,b์ ๊ฐ์
0~255(8bit ๊ธฐ์ค์ผ๋ก ํํ๊ฐ๋ฅํ ๋ชจ๋ ์)๋ฅผ ๋ฃ๊ณ ์ธ์ a๊ฐ๋ ์ํ๊ฐ์ ๋ณ์๋ฅผ ์ฃผ๊ธฐ ์ํด ๋๋ค ์์ฑํด์ ๋ฃ์ต๋๋ค.- ๋๋คํ ์์น์์ ์์ฑ๋๋๋ก
x_pos์y_pos์๋ ๋๋ค๊ฐ์ ๋ฃ์ต๋๋ค.

function setup() {
createCanvas(800, 600);
background(23);
noLoop();
}
function draw() {
noStroke();
for (let i = 0; i < 5000; i++) {
let probability = random();
let color_value;
if (probability < 0.5) color_value = color(200, 200, 200);
else if (probability < 0.7) color_value = color(10, 180, 170);
else color_value = color(10, 90, 80);
fill(color_value);
ellipse(random(width), random(height), 7, 7);
}
}
random()ํจ์๋ก 0~1 ์ฌ์ด์ ์ค์๋ฅผ ์ป๊ณ , ๊ทธ ๊ฐ์probability์ ์ ์ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณcolor_value๋ณ์๋ฅผ ์์ฑํฉ๋๋ค.- ์ด์
if์else if,else๋ฅผ ์ฌ์ฉํด์ 0~1 ์ฌ์ด๋ฅผ ์ธ ๊ตฌํ์ผ๋ก ๋๋๊ณ ์ฐ๋ฆฌ๊ฐ ์ป์ ๋๋ค๊ฐ์ ๋ฐ๋ผ์ ๋ฏธ๋ฆฌ ์ ํด๋์color(r,g,b)๊ฐ์ ๋ถ์ฌํฉ๋๋ค. ์ด ๊ฐ์color_value๋ณ์์ ๋งค ํ์ฐจ๋ง๋คi๊ฐ์ด ์ฆ๊ฐํ ๋๋ง๋คfill(color_value)๋ฉ์๋๋ก ์ ๋ค์ ์์ด ์น ํด์ง ๋ ์ฌ์ฉ๋ฉ๋๋ค.- ์ธ ์ข ๋ฅ์ ์๊น ์ ๋ค์ ์ ํด์ง ์บ๋ฒ์ค ํฌ๊ธฐ ๋ด์์ ๋ฌด์์ ์ขํ(x, y)์ ์ ํด์ง ๋ฐ์ง๋ฆ์ผ๋ก ๋ง๋ค์ด์ง๋๋ค.

function setup() {
createCanvas(800, 800);
background(23);
noLoop();
}
function draw() {
// ์์ ํ๋ ํธ ์ ์ (๋ถํฌ๋ช
๋ ์ถ๊ฐ)
let palette = [
color(255, 240, 0, 180),
color(255, 200, 0, 180),
color(255, 160, 0, 180),
color(255, 100, 0, 180),
color(255, 50, 0, 180),
];
noStroke();
for (let i = 0; i < 2000; i++) {
let idx = int(random(palette.length));
fill(palette[idx]);
// x, y๋ฅผ 10๋จ์๋ก ๋ง์ถ๊ธฐ
let x = int(random(width / 10)) * 10;
let y = int(random(height / 10)) * 10;
ellipse(x, y, 10, 10);
}
}
- ์ฌ๊ธฐ์๋ ๋๋คํ ์ค์๊ฐ ์๋ ์ ์๋ฅผ ๋ฐํํ๋๋ก ํฉ๋๋ค.
random(a, b)โ a ์ด์ b ๋ฏธ๋ง์ ์ค์ ๋ฐํ
int(random(a, b))โ a ์ด์ b ๋ฏธ๋ง์ ์ ์ ๋ฐํ (์์์ ์๋ ๋ฒ๋ฆผ)
floor(random(a, b))โ ์์ ๋์ผํ์ง๋ง ํญ์ ๋ด๋ฆผ ์ฒ๋ฆฌ
ceil(random(a, b))โ ์ฌ๋ฆผ ์ฒ๋ฆฌ (b๊ฐ ํฌํจ๋ ์ ์์)- ์ด๋ ๊ฒ ๋ฌด์์ ์๊ฐ ๋ฐํ๋๋ฉด ๊ฑฐ๊ธฐ์ 10์ ๊ณฑํด 1๋จ์๊ฐ ์๋๋ผ 10๋จ์๋ก ์์น๋ฅผ ๋ค๋ฃฐ ์ ์์ต๋๋ค. (10ํฝ์ ์ ๊ฒฉ์์ ๋ง์ถ์ด ๋ํ ๋ฐฐ์น)
- ์์ ์ฑ์ธ ๋์๋ ๋๋คํ RGB ๊ฐ ๋์ ์ ๋ช๊ฐ์ง ์์ ํ๋ ํธ๋ฅผ
palette๋ผ๋ ์ด๋ฆ์ ๋ฐฐ์ด(list)์ ์ ์ฅํฉ๋๋ค.int(random(palette.length))๋0๋ถํฐpalette.length - 1์ฌ์ด์ ์ ์๋ฅผ ๋ฐํํ๋ ์ญํ ์ ํฉ๋๋ค. ๋ฆฌ์คํธ์ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.

function setup() {
createCanvas(800, 400);
background(23);
noLoop();
}
function draw() {
noStroke();
translate(width / 2, height / 2);
for (let i = 0; i < 10000; i++) {
let x_pos = randomGaussian(0, 60);
let y_pos = randomGaussian(0, 60);
fill(30, 180, 170, 90);
ellipse(x_pos, y_pos, 6, 6);
}
}
- ๊ฐ์ฐ์์ ๋ถํฌ (์ข ๋ชจ์์ ์ ๊ท ๋ถํฌ)๋ฅผ ์ด์ฉํด ์ค์ฌ ๊ทผ์ฒ์ ์ ๋ค์ ๋ฐ์งํด์ ์์ฑํ๋ ๋ฐฉ์์ ๋๋ค.
randomGaussian(mean, sd)
โ ํ๊ท (mean)์ ์ค์ฌ์ผ๋ก, ํ์คํธ์ฐจ(sd)์ ๋ฐ๋ผ ํผ์ง๋ ์ ๊ท๋ถํฌ ๋๋ค ๊ฐ์ ์์ฑํฉ๋๋ค.
์ฆ, ๋๋ถ๋ถ์ ์ ์ (0, 0) ๊ทผ์ฒ์ ๋ชฐ๋ฆฌ๊ณ , ๊ฐ๋์ฉ ๋ฉ๋ฆฌ ๋จ์ด์ง ์ ์ด ์๊ธฐ๊ฒ ๋ฉ๋๋ค.translate(width / 2, height / 2)
โ ์ขํ๊ณ์ ์์ ์ ์บ๋ฒ์ค ์ค์์ผ๋ก ์ด๋์์ผ์,(0,0)์ค์ฌ์ ๊ธฐ์ค์ผ๋ก ๋ถํฌํ๊ฒ ๋ง๋ญ๋๋ค.- ์ด๋ ๊ฒ
x_pos์y_pos๋ฅผ ์ป์ ํ ๋ถํฌ๋ช ๋๊ฐ ์๋ ์์ ์ ํ ํw=6,h=6ํฌ๊ธฐ์ ์ํ์ ์ํํ๋ฉฐ ๊ทธ๋ฆฝ๋๋ค.
์ ๋ค์ด ์ฌ๋ฌ "์ธต"์ผ๋ก ํผ์ง๋ ๊น์ด๊ฐ์ ๋ด๋ ค๋ฉด ์๋์ ๊ฐ์ด ํ ์ ์์ต๋๋ค.

function setup() {
createCanvas(1200, 1200);
colorMode(HSB, 360, 100, 100, 100);
background(5);
noLoop();
noStroke();
translate(width / 2, height / 2);
for (let layer = 0; layer < 5; layer++) {
let sd = 25 + layer * 40;
let alpha = 100 - layer * 15;
let hue = (30 + layer * 60) % 360;
fill(hue, 80, 100, alpha);
for (let i = 0; i < 10000; i++) {
let x_pos = randomGaussian(0, sd);
let y_pos = randomGaussian(0, sd);
ellipse(x_pos, y_pos, random(2, 5));
}
}
}
์ด ์ฝ๋์์๋ ๋ ์ด์ด๋ฅผ 5๊ฐ ์ ํ๊ณ , ๋ฐ๋ณต๋ฌธ์ ํตํด ๋ ์ด์ด๋ง๋ค ์ด๋ค ๋ณํ๋ฅผ ์ค ์ง ๊ธฐ์ ํฉ๋๋ค.
ํ์คํธ์ฐจ= ๊ธฐ์ค ํ์คํธ์ฐจ + ๋ ์ด์ด ๊น์ด์ ๋ฐ๋ฅธ ์์น ์ฆ๊ฐ
-> ๋ ๋๊ฒ ํผ์ง๋๋ก (30, 50, 70, 90, 110)ํฌ๋ช ๋= ํฌ๋ช ๋ 100์์ ๋ ์ด์ด ๊น์ด์ ๋ฐ๋ผ ์์น๋ฅผ ์ฐจ๊ฐ
-> ๋ ํฌ๋ช ํด์ง๋๋ก (100, 90, 80, 70, 60)์์= 200์ ๊ธฐ์ค์ผ๋ก ํด์ ๋ ์ด์ด๋ง๋ค ๋ค๋ฅธ ์์ฑ์ ๊ฐ์ง๋๋ก 360๋๋ฅผ ์ํ
-> (200, 225, 250, 275, 300๋)- ๊ทธ ํ์ ๊ฐ ๋ ์ด์ด๋ง๋ค 1500๊ฐ์ ์ ์ ์์ฑํ๋ ๋ฐ๋ณต๋ฌธ์ ํตํด ์ ๊ท๋ถํฌ์ ๋ฐ๋ฅด๋ X,Y ๊ฐ์ ์ป์ด ์ ํด์ง ์ฌ์ด์ฆ๋ก ์์ ๊ทธ๋ฆฝ๋๋ค.

function setup() {
createCanvas(1200, 1200);
colorMode(HSB, 360, 100, 100, 100);
background(0, 0, 5); // ์ด๋์ด ๋ฐฐ๊ฒฝ
noLoop();
noStroke();
// ์บ๋ฒ์ค๋ฅผ 4๊ฐ์ ๊ตฌ์ญ์ผ๋ก ๋๋์ด ๋ค์ํ ๋๋ค ํจํดๅฑ็คบ
drawRandomWalk(300, 300);
drawParticleSystem(900, 300);
drawNoiseField(300, 900);
drawGaussianClusters(900, 900);
}
// 1. ๋๋ค ์ํฌ (Random Walk)
function drawRandomWalk(x, y) {
push();
translate(x, y);
let posX = 0;
let posY = 0;
let hue = 200; // ํ๋์ ๊ณ์ด
for (let i = 0; i < 1000; i++) {
// ๊ฐ ๊ฑธ์๋ง๋ค ์์ ๋ณํ
fill(hue, 80, 100, 80);
// ๋๋คํ ๋ฐฉํฅ์ผ๋ก ์ด๋
posX += random(-15, 15);
posY += random(-15, 15);
// ์ ์ ์ปค์ง๋ ์
ellipse(posX, posY, i * 0.05 + 2);
// ์์ ๋ณํ
hue = (hue + random(1, 3)) % 360;
}
pop();
}
// 2. ํํฐํด ์์คํ
(Particle System)
function drawParticleSystem(x, y) {
push();
translate(x, y);
for (let i = 0; i < 300; i++) {
// ๋๋คํ ์์ ์์น
let angle = random(TWO_PI);
let distance = random(50, 150);
let startX = cos(angle) * distance;
let startY = sin(angle) * distance;
let hue = random(0, 60); // ๋นจ๊ฐ-์ฃผํฉ ๊ณ์ด
let life = random(50, 100);
// ํํฐํด ๊ถค์ ์๋ฎฌ๋ ์ด์
for (let j = 0; j < life; j++) {
let alpha = map(j, 0, life, 100, 10); // ์ ์ ํฌ๋ฏธํด์ง
fill(hue, 90, 100, alpha);
// ๋๋คํ ์์ง์
startX += random(-3, 3);
startY += random(-3, 3);
ellipse(startX, startY, map(j, 0, life, 8, 2)); // ์ ์ ์์์ง
}
}
pop();
}
// 3. ๋
ธ์ด์ฆ ํ๋ (Noise Field)
function drawNoiseField(x, y) {
push();
translate(x, y);
let time = random(1000);
for (let i = -200; i <= 200; i += 10) {
for (let j = -200; j <= 200; j += 10) {
// ํผ๋ฆฐ ๋
ธ์ด์ฆ๋ฅผ ์ฌ์ฉํ ์์ฐ์ค๋ฌ์ด ๋๋ค
let noiseVal = noise(i * 0.05, j * 0.05, time);
let size = map(noiseVal, 0, 1, 2, 7);
let hue = map(noiseVal, 0, 1, 120, 280); // ์ด๋ก-๋ณด๋ผ ๊ณ์ด
fill(hue, 80, 100, 90);
ellipse(i, j, size);
// ๋
ธ์ด์ฆ๋ฅผ ์ด์ฉํ ํ์ ๊ฐ๋
let angle = noiseVal * TWO_PI * 2;
let length = size * 2;
stroke(hue, 80, 100, 70);
strokeWeight(2);
line(i, j, i + cos(angle) * length, j + sin(angle) * length);
noStroke();
}
}
pop();
}
// 4. ๊ฐ์ฐ์์ ํด๋ฌ์คํฐ (Gaussian Clusters)
function drawGaussianClusters(x, y) {
push();
translate(x, y);
// 3๊ฐ์ ํด๋ฌ์คํฐ ์์ฑ
for (let cluster = 0; cluster < 3; cluster++) {
let clusterX = random(-200, 200);
let clusterY = random(-200, 200);
let hue = random(300, 360); // ๋ถํ-๋ณด๋ผ ๊ณ์ด
for (let i = 0; i < 500; i++) {
// ์ ๊ท๋ถํฌ๋ฅผ ๋ฐ๋ฅด๋ ์์น
let x_pos = randomGaussian(clusterX, 40);
let y_pos = randomGaussian(clusterY, 40);
// ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ํฌ๋ช
๋ ๋ณํ
let distance = dist(x_pos, y_pos, clusterX, clusterY);
let alpha = map(distance, 0, 100, 100, 20);
// ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ํฌ๊ธฐ ๋ณํ
let size = map(distance, 0, 100, 8, 2);
fill(hue, 70, 100, alpha);
ellipse(x_pos, y_pos, size);
}
}
pop();
}
Cargo.toml:
[dependencies]
nannou = "0.19"
gif = "0.13"
image = "0.25"
nannou_egui = "0.19.0"
rand = "0.9.0"
noise = "0.9.0"
rand_distr = "0.5.1"
use nannou::prelude::*;
use rand::Rng; // rand 0.9.0 ๊ธฐ์ค
fn main() {
nannou::app(model).update(update).run();
}
struct Model;
fn model(app: &App) -> Model {
app.new_window()
.view(view)
.size(400, 400)
.title("Uniform Random Example")
.build()
.unwrap();
Model
}
fn update(_app: &App, _model: &mut Model, _update: Update) {}
fn view(app: &App, _model: &Model, frame: Frame) {
// ์ฒซ ๋ฒ์งธ ํ๋ ์๋ง ๊ทธ๋ฆฌ๋๋ก
if frame.nth() > 0 {
return;
}
let draw = app.draw();
draw.background().color(WHITE);
let mut rng = rand::rng(); // thread_rng โ rng
for _ in 0..500 {
let x = rng.random_range(-200.0..200.0);
let y = rng.random_range(-200.0..200.0);
let r = rng.random_range(0.0..1.0);
let g = rng.random_range(0.0..1.0);
let b = rng.random_range(0.0..1.0);
draw.ellipse()
.x_y(x, y)
.w_h(8.0, 8.0)
.rgba(r, g, b, 0.7);
}
draw.to_frame(app, &frame).unwrap();
}
use nannou::prelude::*;
use rand::Rng; // rand = "0.9.0"
fn main() {
nannou::app(model).update(update).run();
}
struct Model;
fn model(app: &App) -> Model {
app.new_window()
.view(view)
.size(400, 400)
.title("Weighted Random Example")
.build()
.unwrap();
Model
}
fn update(_app: &App, _model: &mut Model, _update: Update) {}
fn view(app: &App, _model: &Model, frame: Frame) {
// ํ ํ๋ ์๋ง ๋ ๋๋ง
if frame.nth() > 0 {
return;
}
let draw = app.draw();
draw.background().color(WHITE);
let mut rng = rand::rng(); // โ
์ต์ API
for _ in 0..400 {
let r: f32 = rng.random(); // 0.0~1.0 ์ฌ์ด ์ค์
let color = if r < 0.7 {
rgba(0.8, 0.2, 0.2, 0.7) // 70%
} else if r < 0.9 {
rgba(0.2, 0.4, 0.8, 0.7) // 20%
} else {
rgba(0.1, 0.8, 0.3, 0.7) // 10%
};
let x = rng.random_range(-200.0..200.0);
let y = rng.random_range(-200.0..200.0);
draw.ellipse()
.x_y(x, y)
.w_h(8.0, 8.0)
.color(color);
}
draw.to_frame(app, &frame).unwrap();
}
use nannou::prelude::*;
use rand_distr::{Normal, Distribution};
fn main() {
nannou::app(model).update(update).run();
}
struct Model;
fn model(app: &App) -> Model {
app.new_window().view(view).size(400, 400).build().unwrap();
Model
}
fn update(_app: &App, _model: &mut Model, _update: Update) {}
fn view(app: &App, _model: &Model, frame: Frame) {
if frame.nth() > 0 {
return;
}
let draw = app.draw();
draw.background().color(WHITE);
let normal = Normal::new(0.0, 60.0).unwrap();
let mut rng = rand::rng();
for _ in 0..1000 {
let x: f32 = normal.sample(&mut rng);
let y: f32 = normal.sample(&mut rng);
draw.ellipse().x_y(x, y).w_h(6.0, 6.0).rgba(0.0, 0.0, 0.0, 0.4);
}
draw.to_frame(app, &frame).unwrap();
}