๐Ÿ”ฎ :: Globular Star Cluster

BamgasiJMยท2025๋…„ 10์›” 16์ผ

Nannou <Generative Art>

๋ชฉ๋ก ๋ณด๊ธฐ
45/55
post-thumbnail

๐Ÿ“ Rust Code

use nannou::prelude::*;
use rand::prelude::*;
use rand_distr::{Normal, Distribution};

#[derive(Clone)]
struct Star {
    position: Vec2,
    radius: f32,
    color: Srgba,
}

struct Model {
    stars: Vec<Star>,
    rotation_speed: f32,
    trail_alpha: f32,
}

impl Model {
    fn new(app: &App) -> Self {
        app.new_window()
            .title("Globular Star Cluster (Refactored)")
            .size(1024, 1024)
            .view(Self::view)
            .build()
            .unwrap();

        const NUM_STARS: usize = 2000;
        const STD_DEV: f32 = 220.0;

        let mut rng = thread_rng();
        let normal = Normal::new(0.0, STD_DEV).unwrap();

        let stars = (0..NUM_STARS)
            .map(|_| {
                let x = normal.sample(&mut rng);
                let y = normal.sample(&mut rng);
                let pos = vec2(x, y);
                let dist_from_center = pos.length();

                let weight = (1.0 - (dist_from_center / (STD_DEV * 3.0)).min(1.0)).powf(2.0);
                let base_radius = rng.gen_range(0.3..=2.5);
                let radius = base_radius * (0.5 + 1.5 * weight);
                let base_alpha = rng.gen_range(0.5..=1.0);
                let alpha = base_alpha * (0.3 + 0.7 * weight);

                let hue_shift = rng.gen_range(-0.05..=0.05);
                let t = weight;
                let color = srgba(
                    0.9 - 0.3 * (1.0 - t) + hue_shift,
                    0.9 - 0.2 * (1.0 - t),
                    1.0 - 0.1 * t,
                    alpha,
                );

                Star {
                    position: pos,
                    radius,
                    color,
                }
            })
            .collect();

        Self {
            stars,
            rotation_speed: 0.002,
            trail_alpha: 0.1,
        }
    }

    fn update(&mut self) {
        let theta = self.rotation_speed;
        let cos_t = theta.cos();
        let sin_t = theta.sin();

        for star in &mut self.stars {
            let pos = star.position;
            star.position = vec2(
                pos.x * cos_t - pos.y * sin_t,
                pos.x * sin_t + pos.y * cos_t,
            );
        }
    }

    fn view(app: &App, model: &Self, frame: Frame) {
        let draw = app.draw();

        // ์ž”์ƒ ํšจ๊ณผ
        draw.rect()
            .wh(app.window_rect().wh())
            .color(srgba(0.0, 0.0, 0.0, model.trail_alpha));

        for star in &model.stars {
            draw.ellipse()
                .xy(star.position)
                .radius(star.radius)
                .color(star.color);

            // ๊ธ€๋กœ์šฐ ํšจ๊ณผ
            draw.ellipse()
                .xy(star.position)
                .radius(star.radius * 1.3)
                .color(srgba(
                    star.color.red,
                    star.color.green,
                    star.color.blue,
                    star.color.alpha * 0.02,
                ));
        }

        draw.to_frame(app, &frame).unwrap();
    }
}

// ==========================
// nannou entry point
// ==========================
fn main() {
    nannou::app(|app| Model::new(app))
        .update(|_app, model, _update| model.update())
        .run();
}

๐Ÿ“ Rust Code + Comment

// Nannou์˜ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๋“ค์„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
// (App, Frame, draw, vec2, srgba, ์ƒ‰์ƒ, ๋„ํ˜• ๋“ฑ)
use nannou::prelude::*;

// ๋‚œ์ˆ˜ ์ƒ์„ฑ์„ ์œ„ํ•œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๋“ค (thread_rng, gen_range ๋“ฑ)
use rand::prelude::*;

// ํ™•๋ฅ  ๋ถ„ํฌ (ํŠนํžˆ ์ •๊ทœ ๋ถ„ํฌ = ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ)๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํฌ๋ ˆ์ดํŠธ
use rand_distr::{Normal, Distribution};

// ๊ฐ ๋ณ„(Star)์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ์ฒด
#[derive(Clone)]
struct Star {
    position: Vec2,  // ๋ณ„์˜ 2D ์œ„์น˜ (x, y ์ขŒํ‘œ)
    radius: f32,     // ๋ณ„์˜ ๋ฐ˜์ง€๋ฆ„ (ํฌ๊ธฐ)
    color: Srgba,    // ๋ณ„์˜ ์ƒ‰์ƒ (RGBA, ์•ŒํŒŒ ์ฑ„๋„ ํฌํ•จ)
}

// ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ชจ๋ธ ๊ตฌ์กฐ์ฒด
struct Model {
    stars: Vec<Star>,       // ํ™”๋ฉด์— ๊ทธ๋ฆด ๋ชจ๋“  ๋ณ„์˜ ๋ชฉ๋ก
    rotation_speed: f32,    // ์ „์ฒด ๋ณ„ ์ง‘ํ•ฉ์˜ ํšŒ์ „ ์†๋„ (๋ผ๋””์•ˆ/ํ”„๋ ˆ์ž„ ๋‹จ์œ„)
    trail_alpha: f32,       // ์ž”์ƒ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ๊ฒ€์€์ƒ‰ ๋ ˆ์ด์–ด์˜ ํˆฌ๋ช…๋„ (0.0 ~ 1.0)
}

// Model ๊ตฌ์กฐ์ฒด์— ๋Œ€ํ•œ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
impl Model {
    // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
    fn new(app: &App) -> Self {
        // Nannou ์ฐฝ์„ ์„ค์ •ํ•˜๊ณ  ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
        app.new_window()
            .title("Globular Star Cluster (Refactored)") // ์ฐฝ ์ œ๋ชฉ
            .size(1024, 1024)                            // ์ฐฝ ํฌ๊ธฐ: 1024x1024 ํ”ฝ์…€
            .view(Self::view)                            // ๋ Œ๋”๋ง์€ Self::view ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ
            .build()
            .unwrap(); // ์ฐฝ ์ƒ์„ฑ ์‹คํŒจ ์‹œ panic (๊ฐ„๋‹จํ•œ ์˜ˆ์ œ์—์„œ๋Š” ํ—ˆ์šฉ)

        // ์ƒ์ˆ˜ ์ •์˜: ๋ณ„์˜ ์ด ๊ฐœ์ˆ˜์™€ ์ •๊ทœ ๋ถ„ํฌ์˜ ํ‘œ์ค€ํŽธ์ฐจ
        const NUM_STARS: usize = 2000;   // ๋ณ„ 2000๊ฐœ ์ƒ์„ฑ
        const STD_DEV: f32 = 220.0;      // ์ •๊ทœ ๋ถ„ํฌ์˜ ํ‘œ์ค€ํŽธ์ฐจ (๋‹จ์œ„: ํ”ฝ์…€)

        // ํ˜„์žฌ ์Šค๋ ˆ๋“œ ์ „์šฉ ๋‚œ์ˆ˜ ์ƒ์„ฑ๊ธฐ ์ƒ์„ฑ
        let mut rng = thread_rng();

        // ํ‰๊ท  0.0, ํ‘œ์ค€ํŽธ์ฐจ STD_DEV์ธ ์ •๊ทœ ๋ถ„ํฌ(๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ) ๊ฐ์ฒด ์ƒ์„ฑ
        // ์ด ๋ถ„ํฌ์—์„œ ์ƒ˜ํ”Œ๋งํ•˜๋ฉด ์ค‘์‹ฌ(0,0) ๊ทผ์ฒ˜์— ๋ฐ€์ง‘๋œ ๊ฐ’๋“ค์ด ๋‚˜์˜ด
        let normal = Normal::new(0.0, STD_DEV).unwrap();

        // ๋ณ„๋“ค์„ ์ •๊ทœ ๋ถ„ํฌ์— ๋”ฐ๋ผ ๋ฌด์ž‘์œ„๋กœ ์ƒ์„ฑ
        let stars = (0..NUM_STARS)
            .map(|_| {
                // X, Y ์ขŒํ‘œ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์ •๊ทœ ๋ถ„ํฌ์—์„œ ์ƒ˜ํ”Œ๋ง โ†’ 2D ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ ํšจ๊ณผ
                let x = normal.sample(&mut rng);
                let y = normal.sample(&mut rng);
                let pos = vec2(x, y); // Vec2 ํƒ€์ž…์œผ๋กœ ์œ„์น˜ ์ƒ์„ฑ

                // ์›์ (0,0)์—์„œ์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
                let dist_from_center = pos.length();

                // ๊ฐ€์ค‘์น˜(weight): ์ค‘์‹ฌ์—์„œ ๋ฉ€์–ด์งˆ์ˆ˜๋ก ์ž‘์•„์ง (0~1)
                // STD_DEV * 3.0 โ‰ˆ 99.7%์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋˜๋Š” ๋ฐ˜๊ฒฝ (3ฯƒ ๊ทœ์น™)
                // .min(1.0)์œผ๋กœ 1์„ ๋„˜์ง€ ์•Š๋„๋ก ๋ณด์žฅ
                // .powf(2.0)๋กœ ์ค‘์‹ฌ ๊ทผ์ฒ˜๊ฐ€ ํ›จ์”ฌ ๋” ๊ฐ•์กฐ๋˜๋„๋ก ๋น„์„ ํ˜• ์กฐ์ •
                let weight = (1.0 - (dist_from_center / (STD_DEV * 3.0)).min(1.0)).powf(2.0);

                // ๊ธฐ๋ณธ ๋ฐ˜์ง€๋ฆ„์„ 0.3~2.5 ์‚ฌ์ด์—์„œ ๋ฌด์ž‘์œ„ ์„ ํƒ
                let base_radius = rng.gen_range(0.3..=2.5);
                // ๊ฐ€์ค‘์น˜์— ๋”ฐ๋ผ ๋ฐ˜์ง€๋ฆ„ ์กฐ์ •: ์ค‘์‹ฌ ๋ณ„์ผ์ˆ˜๋ก ๋” ํฌ๊ฒŒ
                let radius = base_radius * (0.5 + 1.5 * weight);

                // ๊ธฐ๋ณธ ์•ŒํŒŒ(ํˆฌ๋ช…๋„)๋ฅผ 0.5~1.0 ์‚ฌ์ด์—์„œ ๋ฌด์ž‘์œ„ ์„ ํƒ
                let base_alpha = rng.gen_range(0.5..=1.0);
                // ๊ฐ€์ค‘์น˜์— ๋”ฐ๋ผ ์•ŒํŒŒ ์กฐ์ •: ์ค‘์‹ฌ ๋ณ„์ผ์ˆ˜๋ก ๋” ๋ถˆํˆฌ๋ช…ํ•˜๊ฒŒ
                let alpha = base_alpha * (0.3 + 0.7 * weight);

                // ์ƒ‰์ƒ ์กฐ์ •: ์ค‘์‹ฌ์€ ํฐ์ƒ‰์— ๊ฐ€๊นŒ์šด ํŒŒ๋ž€๋น›, ๊ฐ€์žฅ์ž๋ฆฌ๋Š” ๋” ํŒŒ๋ž€์ƒ‰
                // hue_shift๋กœ ์•ฝ๊ฐ„์˜ ์ƒ‰์ƒ ๋ณ€๋™์„ ์ค˜ ์ž์—ฐ์Šค๋Ÿฌ์›€ ์ถ”๊ฐ€
                let hue_shift = rng.gen_range(-0.05..=0.05);
                let t = weight; // ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด weight๋ฅผ t๋กœ ๋ณต์‚ฌ
                let color = srgba(
                    0.9 - 0.3 * (1.0 - t) + hue_shift, // ๋นจ๊ฐ•: ์ค‘์‹ฌ์ผ์ˆ˜๋ก ๋ฐ์Œ
                    0.9 - 0.2 * (1.0 - t),             // ์ดˆ๋ก
                    1.0 - 0.1 * t,                     // ํŒŒ๋ž‘: ์ค‘์‹ฌ์ผ์ˆ˜๋ก ์•ฝ๊ฐ„ ์–ด๋‘์›€
                    alpha,                             // ์œ„์—์„œ ๊ณ„์‚ฐํ•œ ์•ŒํŒŒ ๊ฐ’ ์‚ฌ์šฉ
                );

                // Star ๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
                Star {
                    position: pos,
                    radius,
                    color,
                }
            })
            .collect(); // Iterator๋ฅผ Vec<Star>๋กœ ๋ณ€ํ™˜

        // Model ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜
        Self {
            stars,
            rotation_speed: 0.002, // ๋งค์šฐ ๋А๋ฆฐ ํšŒ์ „ ์†๋„ (๋ผ๋””์•ˆ/ํ”„๋ ˆ์ž„)
            trail_alpha: 0.1,      // ์ž”์ƒ ํšจ๊ณผ์˜ ํˆฌ๋ช…๋„: 10% ๋ถˆํˆฌ๋ช…
        }
    }

    // ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ํ˜ธ์ถœ๋˜์–ด ๋ณ„๋“ค์˜ ์œ„์น˜๋ฅผ ์—…๋ฐ์ดํŠธ (ํšŒ์ „ ์ ์šฉ)
    fn update(&mut self) {
        let theta = self.rotation_speed; // ํšŒ์ „ ๊ฐ๋„ (๋งค ํ”„๋ ˆ์ž„ ์ฆ๊ฐ€๋Ÿ‰)
        let cos_t = theta.cos();         // cos(ฮธ) โ€” ํšŒ์ „ ํ–‰๋ ฌ ๊ณ„์‚ฐ์„ ์œ„ํ•ด ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ
        let sin_t = theta.sin();         // sin(ฮธ)

        // ๋ชจ๋“  ๋ณ„์— ๋Œ€ํ•ด 2D ํšŒ์ „ ๋ณ€ํ™˜ ์ ์šฉ
        for star in &mut self.stars {
            let pos = star.position;
            // 2D ํšŒ์ „ ๊ณต์‹: 
            // x' = x*cosฮธ - y*sinฮธ
            // y' = x*sinฮธ + y*cosฮธ
            star.position = vec2(
                pos.x * cos_t - pos.y * sin_t,
                pos.x * sin_t + pos.y * cos_t,
            );
        }
    }

    // ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ํ™”๋ฉด์„ ๊ทธ๋ฆฌ๋Š” ํ•จ์ˆ˜ (๋ Œ๋”๋ง)
    fn view(app: &App, model: &Self, frame: Frame) {
        let draw = app.draw(); // ๊ทธ๋ฆฌ๊ธฐ ์ปจํ…์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ

        // [์ž”์ƒ ํšจ๊ณผ] ์ด์ „ ํ”„๋ ˆ์ž„์˜ ๋‚ด์šฉ์„ ์™„์ „ํžˆ ์ง€์šฐ์ง€ ์•Š๊ณ ,
        // ์•ฝ๊ฐ„ ํˆฌ๋ช…ํ•œ ๊ฒ€์€์ƒ‰ ์‚ฌ๊ฐํ˜•์„ ๋ฎ์–ด ์„œ์„œํžˆ ํ๋ ค์ง€๊ฒŒ ๋งŒ๋“ฆ
        draw.rect()
            .wh(app.window_rect().wh()) // ์ฐฝ ์ „์ฒด ํฌ๊ธฐ
            .color(srgba(0.0, 0.0, 0.0, model.trail_alpha)); // ๊ฒ€์€์ƒ‰ + ํˆฌ๋ช…๋„

        // ๋ชจ๋“  ๋ณ„์„ ์ˆœํšŒํ•˜๋ฉฐ ๊ทธ๋ฆฌ๊ธฐ
        for star in &model.stars {
            // 1. ๋ณ„์˜ ๋ณธ์ฒด ๊ทธ๋ฆฌ๊ธฐ
            draw.ellipse()
                .xy(star.position)   // ์œ„์น˜
                .radius(star.radius) // ๋ฐ˜์ง€๋ฆ„
                .color(star.color);  // ์ƒ‰์ƒ (์•ŒํŒŒ ํฌํ•จ)

            // 2. ๊ธ€๋กœ์šฐ(Glow) ํšจ๊ณผ: ๋ณธ์ฒด๋ณด๋‹ค ์•ฝ๊ฐ„ ํฐ ํƒ€์›์„ ๋งค์šฐ ํˆฌ๋ช…ํ•˜๊ฒŒ ๊ทธ๋ ค ๋น› ๋ฒˆ์ง ํ‘œํ˜„
            draw.ellipse()
                .xy(star.position)
                .radius(star.radius * 1.3) // ์•ฝ 30% ๋” ํฐ ๋ฐ˜์ง€๋ฆ„
                .color(srgba(
                    star.color.red,
                    star.color.green,
                    star.color.blue,
                    star.color.alpha * 0.02, // ์•ŒํŒŒ๋ฅผ 2%๋กœ ๋‚ฎ์ถค โ†’ ํฌ๋ฏธํ•œ ๊ด‘์ฑ„
                ));
        }

        // ๊ทธ๋ฆฐ ๋‚ด์šฉ์„ ์‹ค์ œ ํ”„๋ ˆ์ž„ ๋ฒ„ํผ์— ์ถœ๋ ฅ
        draw.to_frame(app, &frame).unwrap();
    }
}

// ==========================
// Nannou ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์ 
// ==========================
fn main() {
    // nannou::app()์œผ๋กœ ์•ฑ ์‹œ์ž‘
    nannou::app(|app| Model::new(app)) // ์ดˆ๊ธฐ ์ƒํƒœ ์ƒ์„ฑ
        .update(|_app, model, _update| model.update()) // ๋งค ํ”„๋ ˆ์ž„ ์—…๋ฐ์ดํŠธ
        .run(); // ์ด๋ฒคํŠธ ๋ฃจํ”„ ์‹œ์ž‘ ๋ฐ ์‹คํ–‰
}

rand_distr = "0.4.3" ํ•„์š”

๋ฐ€๋„ ๊ฐ€์ค‘์น˜ (Distance Weighting) : ์ค‘์‹ฌ์—์„œ ๋ฉ€์–ด์งˆ์ˆ˜๋ก ๋ฐ˜์ง€๋ฆ„๊ณผ ์•ŒํŒŒ๊ฐ’์ด ์ค„์–ด๋“ฆ
์ƒ‰์ƒ ๋ณ€ํ™” : ์ค‘์‹ฌ๋ถ€๋Š” ํฐ์ƒ‰, ์™ธ๊ณฝ์€ ํ‘ธ๋ฅธ์ƒ‰/๋…ธ๋ž€๋น› ๋žœ๋ค ์„ž๊ธฐ
ํŠธ๋ ˆ์ผ ํšจ๊ณผ (Motion Blur) : ๋งค ํ”„๋ ˆ์ž„ ์‚ด์ง ์–ด๋‘์šด ๋ฐ˜ํˆฌ๋ช… ๋ ˆ์ด์–ด๋ฅผ ๋ง๊ทธ๋ ค ๋ถ€๋“œ๋Ÿฌ์šด ์ž”์ƒ ์ƒ์„ฑ
๋ถ€๋“œ๋Ÿฌ์šด ํ™•์‚ฐ ํšจ๊ณผ : ์•ŒํŒŒ๊ฐ’์„ ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ˜ ๊ณก์„ ์œผ๋กœ ๊ณ„์‚ฐ (์˜ˆ: alpha = exp(-rยฒ / (2ฯƒยฒ)))


๐Ÿ“Œ ์ „์ฒด ์ฝ”๋“œ ๊ฐœ์š”
์ด ํ”„๋กœ๊ทธ๋žจ์€ ๊ตฌ์ƒ์„ฑ๋‹จ(Globular Star Cluster)์ฒ˜๋Ÿผ ๋ณด์ด๋Š” 2D ๋ณ„๋“ค์˜ ์ง‘ํ•ฉ์„ ํ™”๋ฉด์— ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

๋ณ„๋“ค์€ ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ(์ •๊ทœ ๋ถ„ํฌ)๋ฅผ ๋”ฐ๋ผ ์ค‘์‹ฌ์—์„œ ๋ฐ€์ง‘๋˜์–ด ๋ฐฐ์น˜๋ฉ๋‹ˆ๋‹ค.
์ „์ฒด ๋ณ„ ์ง‘ํ•ฉ์ด ์ฒœ์ฒœํžˆ ํšŒ์ „ํ•˜๋ฉฐ, ์ž”์ƒ ํšจ๊ณผ(trail)์™€ ๊ธ€๋กœ์šฐ(glow) ํšจ๊ณผ๋ฅผ ํ†ตํ•ด ์‹œ๊ฐ์ ์œผ๋กœ ์•„๋ฆ„๋‹ต๊ฒŒ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค.
์ƒ‰์ƒ๊ณผ ํฌ๊ธฐ๋Š” ์ค‘์‹ฌ์—์„œ์˜ ๊ฑฐ๋ฆฌ์— ๋”ฐ๋ผ ๊ฐ€์ค‘์น˜(weight)๋ฅผ ์ ์šฉํ•ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.
๐Ÿ“ฆ ์‚ฌ์šฉ๋œ ํฌ๋ ˆ์ดํŠธ ์„ค๋ช…
1. nannou::prelude::
Nannou ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋“ค์„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
App, Frame, draw, vec2, srgba, rect, ellipse ๋“ฑ ๊ทธ๋ž˜ํ”ฝ ๋ฐ ์•ฑ ์ œ์–ด ๊ธฐ๋Šฅ ํฌํ•จ.
2. rand::prelude::

๋‚œ์ˆ˜ ์ƒ์„ฑ์„ ์œ„ํ•œ rand ํฌ๋ ˆ์ดํŠธ์˜ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ.
thread_rng() ๋“ฑ์œผ๋กœ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๋‚œ์ˆ˜ ์ƒ์„ฑ๊ธฐ๋ฅผ ์‚ฌ์šฉ.
3. rand_distr::{Normal, Distribution}
ํ™•๋ฅ  ๋ถ„ํฌ๋ฅผ ์œ„ํ•œ ํ™•์žฅ ํฌ๋ ˆ์ดํŠธ.
Normal์€ ์ •๊ทœ ๋ถ„ํฌ(๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ)๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
Distribution ํŠธ๋ ˆ์ž‡์„ ํ†ตํ•ด .sample() ๋ฉ”์„œ๋“œ๋กœ ๋‚œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ” ์ฐธ๊ณ : rand_distr์€ rand์˜ ํ™•์žฅ์œผ๋กœ, ๋‹ค์–‘ํ•œ ํ™•๋ฅ  ๋ถ„ํฌ(์ •๊ทœ, ๊ฐ๋งˆ, ๋ฒ ํƒ€ ๋“ฑ)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๊ณต์‹ ๋ฌธ์„œ: https://docs.rs/rand_distr/latest/rand_distr/

  1. ์ •๊ทœ ๋ถ„ํฌ(๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ)
    ์ •์˜: ํ‰๊ท (ฮผ)๊ณผ ํ‘œ์ค€ํŽธ์ฐจ(ฯƒ)๋กœ ์ •์˜๋˜๋Š” ์—ฐ์† ํ™•๋ฅ  ๋ถ„ํฌ.
    ํŠน์ง•: ์ข… ๋ชจ์–‘, ์ค‘์‹ฌ์— ์ง‘์ค‘, ยฑ1ฯƒ: 68%, ยฑ2ฯƒ: 95%, ยฑ3ฯƒ: 99.7%
    ์‹œ๊ฐํ™”: https://en.wikipedia.org/wiki/Normal_distribution
profile
Coding Art with Blender / oF / Processing / p5.js / nannou

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