📝 Rust Code
use nannou::prelude::*;
use nannou::noise::{NoiseFn, Perlin, Seedable};
struct Model {
smooth_points: Vec<Vec2>,
noise: Perlin,
}
fn main() {
nannou::app(model).update(update).run();
}
fn model(app: &App) -> Model {
app.new_window()
.size(1080, 1080)
.view(view)
.title("Organic Noise Blob")
.build()
.unwrap();
let noise = Perlin::new().set_seed(random());
Model {
smooth_points: Vec::new(),
noise,
}
}
fn update(app: &App, model: &mut Model, _update: Update) {
let num_points = 120;
let time = app.time * 0.5;
let mut raw_points = Vec::with_capacity(num_points);
for i in 0..num_points {
let theta = i as f32 * TAU / num_points as f32;
let noise_val = model.noise.get([
(theta.cos() as f64) + 1.0,
(theta.sin() as f64) + 1.0,
time as f64
]) as f32;
let r = 300.0 + noise_val * 150.0;
raw_points.push(pt2(theta.cos() * r, theta.sin() * r));
}
model.smooth_points = catmull_rom_spline(&raw_points, 4);
}
fn view(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().color(BLACK);
draw.polyline()
.weight(5.0)
.color(WHITE)
.points_closed(model.smooth_points.iter().cloned());
draw.to_frame(app, &frame).unwrap();
}
fn catmull_rom_spline(points: &[Vec2], segments: usize) -> Vec<Vec2> {
let n = points.len();
let mut smoothed = Vec::with_capacity(n * segments);
for i in 0..n {
let p0 = points[(i + n - 1) % n];
let p1 = points[i];
let p2 = points[(i + 1) % n];
let p3 = points[(i + 2) % n];
for j in 0..segments {
let t = j as f32 / segments as f32;
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);
smoothed.push(pt2(x, y));
}
}
smoothed
}