๐Ÿ”ฎ :: Spinning Spiral Noise

BamgasiJMยท2025๋…„ 9์›” 21์ผ

Nannou <Generative Art>

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

๐Ÿ“ Rust Code

use nannou::prelude::*;
use nannou::noise::*;

struct Model {
    angle: f32,
    spiral_params: SpiralParams,
    noise: Perlin,
    time: f32,
}

struct SpiralParams {
    turns: f32,
    points_count: usize,
    spacing: f32,
    max_radius: f32,
    noise_strength: f32,
    noise_speed: f32,
}

impl Default for SpiralParams {
    fn default() -> Self {
        Self {
            turns: 35.0,
            points_count: 5000,
            spacing: 3.0,
            max_radius: 500.0,
            noise_strength: 20.0,
            noise_speed: 2.0,
        }
    }
}

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

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .title("ํ”๋“ค๋ฆฌ๋Š” ๋‚˜์„  feat Catmull-Rom Spline")
        .size(800, 800)
        .view(view)
        .build()
        .unwrap();

    Model {
        angle: 0.0,
        spiral_params: SpiralParams::default(),
        noise: Perlin::new(),
        time: 0.0,
    }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    model.angle -= 0.01;
    model.time += 0.01;
}

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    
    draw.background().color(BLACK);
    let draw = draw.rotate(model.angle);
    
    let params = &model.spiral_params;
    let max_t = params.turns * TAU;
    let common_time = model.time * params.noise_speed;
    
    // ์ ๋“ค ์ƒ์„ฑ
    let points: Vec<Point2> = (0..params.points_count)
        .filter_map(|i| {
            let t = (i as f32 / params.points_count as f32) * max_t;
            let base_r = params.spacing * t;
            if base_r > params.max_radius {
                return None;
            }
            
            let noise_val = model.noise.get([
                (i as f32 * 0.05) as f64,
                common_time as f64
            ]) as f32;
            
            let r = base_r + noise_val * params.noise_strength;
            Some(pt2(r * t.cos(), r * t.sin()))
        })
        .collect();
    
    // ๋ถ€๋“œ๋Ÿฌ์šด ๊ณก์„ ์„ ์œ„ํ•ด Catmull-Rom ์Šคํ”Œ๋ผ์ธ ๋ฐฉ์‹์œผ๋กœ ์„  ๊ทธ๋ฆฌ๊ธฐ
    if points.len() > 3 {
        for i in 1..points.len() - 2 {
            let progress = i as f32 / points.len() as f32;
            let alpha = map_range(progress, 0.0, 1.0, 0.1, 0.9);
            let hue = map_range(progress, 0.0, 1.0, 0.8, 0.5);
            let saturation = map_range(progress, 0.0, 1.0, 0.3, 0.8);
            let lightness = map_range(progress, 0.0, 1.0, 0.3, 0.7);
            let weight = map_range(progress, 0.0, 1.0, 0.3, 2.5);
            
            // ํ˜„์žฌ ์ ๊ณผ ์ด์ „, ๋‹ค์Œ ์ ๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋“œ๋Ÿฌ์šด ์„ ๋ถ„ ์ƒ์„ฑ
            let p0 = points[i - 1];
            let p1 = points[i];
            let p2 = points[i + 1];
            let p3 = points[i + 2];
            
            // Catmull-Rom ์Šคํ”Œ๋ผ์ธ์„ ์œ„ํ•œ ๋ณด๊ฐ„
            for j in 0..5 {
                let t = j as f32 / 4.0;
                let t2 = t * t;
                let t3 = t2 * t;
                
                let x = 0.5 * ((2.0 * p1.x) + 
                              (-p0.x + p2.x) * t +
                              (2.0 * p0.x - 5.0 * p1.x + 4.0 * p2.x - p3.x) * t2 +
                              (-p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x) * t3);
                
                let y = 0.5 * ((2.0 * p1.y) + 
                              (-p0.y + p2.y) * t +
                              (2.0 * p0.y - 5.0 * p1.y + 4.0 * p2.y - p3.y) * t2 +
                              (-p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y) * t3);
                
                let current_point = pt2(x, y);
                
                if j > 0 {
                    let prev_point = {
                        let prev_t = (j - 1) as f32 / 4.0;
                        let prev_t2 = prev_t * prev_t;
                        let prev_t3 = prev_t2 * prev_t;
                        
                        let prev_x = 0.5 * ((2.0 * p1.x) + 
                                          (-p0.x + p2.x) * prev_t +
                                          (2.0 * p0.x - 5.0 * p1.x + 4.0 * p2.x - p3.x) * prev_t2 +
                                          (-p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x) * prev_t3);
                        
                        let prev_y = 0.5 * ((2.0 * p1.y) + 
                                          (-p0.y + p2.y) * prev_t +
                                          (2.0 * p0.y - 5.0 * p1.y + 4.0 * p2.y - p3.y) * prev_t2 +
                                          (-p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y) * prev_t3);
                        
                        pt2(prev_x, prev_y)
                    };
                    
                    draw.line()
                        .start(prev_point)
                        .end(current_point)
                        .weight(weight * 0.8) // ์•ฝ๊ฐ„ ๋” ๊ฐ€๋Š” ์„ 
                        .color(hsla(hue, saturation, lightness, alpha * 0.8));
                }
            }
        }
    }
    
    // ์ค‘์‹ฌ์ 
    draw.ellipse()
        .radius(3.0)
        .color(hsla(0.6, 0.8, 0.9, 0.8));
    
    draw.to_frame(app, &frame).unwrap();
}

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

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