๐ŸŽ“ 2์ฃผ์ฐจ: ๋ฌด์ž‘์œ„์„ฑ (Randomness)

BamgasiJMยท2025๋…„ 11์›” 2์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
13/67
post-thumbnail

Randomness์˜ ๊ฐœ๋…

๋žœ๋ค์ด๋ž€ ๋ฌด์ž‘์œ„์„ฑ, ๋น„๊ฒฐ์ •์„ฑ, ์˜ˆ์ธก๋ถˆ๊ฐ€๋Šฅ์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, "์–ด๋–ค ๊ทœ์น™๋„ ์—†์ด ํฉ์–ด์ง€๋Š” ๊ฐ’"์„ ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ์ด์ง€์š”. ์—ฌ๋Ÿฌ ๋ฐฉ์‹์œผ๋กœ ๋ฌด์ž‘์œ„์˜ ์ •์ˆ˜, ์‹ค์ˆ˜๋ฅผ ํŠน์ • ๋ฒ”์œ„ ์•ˆ์—์„œ ์ถ”์ถœํ•˜๊ณ  ๊ทธ๊ฒƒ์„ ์•„ํŠธ์›Œํฌ ์ œ์ž‘์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ด๋ฒˆ ์ฑ•ํ„ฐ์˜ ์ฃผ์ œ์ž…๋‹ˆ๋‹ค.

p5.js์—์„œ๋Š” ์ด๋Ÿฐ ํ•จ์ˆ˜๋“ค๋กœ ๋ฌด์ž‘์œ„์„ฑ์„ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.()์•ˆ์˜ ์ธ์ˆ˜๋Š” ํ•จ์ˆ˜๋งˆ๋‹ค ์ •ํ•ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

  • random() โ†’ ์™„์ „ํ•œ ๊ท ์ผ ๋ถ„ํฌ (Uniform random)

  • randomGaussian() โ†’ ์ •๊ทœ๋ถ„ํฌ์— ๊ธฐ๋ฐ˜ ๋ฌด์ž‘์œ„ ๋ถ„ํฌ

  • randomSeed() โ†’ ๋žœ๋ค ์‹œ๋“œ ๊ณ ์ •

  • shuffle(), randomChoice() โ†’ ๋ฐฐ์—ด์„ ์„ž๊ฑฐ๋‚˜ ์ž„์˜๋กœ ์ถ”์ถœ

๐ŸŸฆ 1. ๊ท ๋“ฑ ๋ถ„ํฌ (Uniform Distribution)

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์—๋„ ๋žœ๋ค๊ฐ’์„ ๋„ฃ์Šต๋‹ˆ๋‹ค.

๐ŸŸฆ 2. ๊ฐ€์ค‘์น˜ ๊ธฐ๋ฐ˜ ๋ฌด์ž‘์œ„ ์„ ํƒ (Weighted Random Choice)

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)์™€ ์ •ํ•ด์ง„ ๋ฐ˜์ง€๋ฆ„์œผ๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

๐ŸŸฆ 3. ๋žœ๋คํ•œ ์ •์ˆ˜ (Random Integer)

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 ์‚ฌ์ด์˜ ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์ŠคํŠธ์˜ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๐ŸŸฆ 4. ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ(Gaussian / Normal Distribution)

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 ๊ฐ’์„ ์–ป์–ด ์ •ํ•ด์ง„ ์‚ฌ์ด์ฆˆ๋กœ ์›์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

๐ŸŸฆ 5. ๋žœ๋ค ์•„ํŠธ ์ข…ํ•ฉ (Assorted random art)

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();
}

nannou

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"

๐ŸŸฆ 1. ๊ท ๋“ฑ ๋ถ„ํฌ (Uniform Distribution)

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();
}

๐ŸŸฆ 2. ๊ฐ€์ค‘์น˜ ๊ธฐ๋ฐ˜ ๋ฌด์ž‘์œ„ ์„ ํƒ (Weighted Random Choice

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();
}

๐ŸŸฆ 4. ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ(Gaussian / Normal Distribution)

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();
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€