๐Ÿ”ฎ :: Random Walker Light Trail

BamgasiJMยท2026๋…„ 1์›” 26์ผ

Nannou <Generative Art>

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

๐Ÿ“ Rust Code

use nannou::noise::{NoiseFn, Perlin};
use nannou::prelude::*;

struct Particle {
    position: Vec2,
    velocity: Vec2,
    history: Vec<Vec2>,
    hue: f32,
}

struct Model {
    particles: Vec<Particle>,
    perlin: Perlin,
    time: f64,
    frame_count: usize,
}

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    app.new_window()
        .size(800, 800)
        .view(view)
        .build()
        .unwrap();

    let perlin = Perlin::new();
    let particles = spawn_particles(&perlin);

    Model {
        particles,
        perlin,
        time: 0.0,
        frame_count: 0,
    }
}

/// ์ƒˆ๋กœ์šด ํญ๋ฐœ์„ ์ค‘์•™์—์„œ ์‹œ์ž‘ํ•˜๋„๋ก ํŒŒํ‹ฐํด ์ƒ์„ฑ
fn spawn_particles(_perlin: &Perlin) -> Vec<Particle> {
    let mut particles = Vec::new();
    let center = pt2(0.0, 0.0);

    for _ in 0..1000 {
        let angle = random_range(0.0, TAU);
        let velocity = vec2(angle.cos(), angle.sin()) * random_range(1.0, 3.0);

        particles.push(Particle {
            position: center,
            velocity,
            history: Vec::new(),
            hue: random_f32(),
        });
    }
    particles
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    model.time += 0.0002;
    model.frame_count += 1;

    // ์ผ์ • ์‹œ๊ฐ„(์˜ˆ: 300ํ”„๋ ˆ์ž„ โ‰ˆ 5์ดˆ)๋งˆ๋‹ค ์ค‘์•™์—์„œ ๋‹ค์‹œ ํญ๋ฐœ
    if model.frame_count % 300 == 0 {
        model.particles = spawn_particles(&model.perlin);
    }

    for p in model.particles.iter_mut() {
        let n = model.perlin.get([
            p.position.x as f64 * 0.005,
            p.position.y as f64 * 0.005,
            model.time,
        ]);

        let angle_offset = map_range(n, -1.0, 1.0, -0.3, 0.3);

        let current_angle = p.velocity.angle();
        let new_angle = current_angle + angle_offset as f32;
        let speed = p.velocity.length() * 1.01; // ์ ์  ๋นจ๋ผ์ง

        p.velocity = vec2(new_angle.cos(), new_angle.sin()) * speed;

        p.position += p.velocity;

        p.history.push(p.position);
        if p.history.len() > 25 {
            p.history.remove(0);
        }
    }
}

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

    // ๋ฐ˜ํˆฌ๋ช… ๊ฒ€์€ ๋ฐฐ๊ฒฝ (์ž”์ƒ ํšจ๊ณผ)
    draw.rect()
        .wh(app.window_rect().wh())
        .color(srgba(0.0, 0.0, 0.0, 0.2));

    // ๊ฐ ํŒŒํ‹ฐํด ๊ถค์  ๊ทธ๋ฆฌ๊ธฐ
    for p in &model.particles {
        if p.history.len() > 1 {
            draw.polyline()
                .weight(0.8)
                .points(p.history.clone())
                .color(hsla(
                    p.hue,
                    0.9,
                    0.6,
                    0.6,
                ));
        }
    }

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

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

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