socchastic somethingorother
This commit is contained in:
54
Cargo.lock
generated
54
Cargo.lock
generated
@@ -129,6 +129,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"minifb",
|
"minifb",
|
||||||
"num",
|
"num",
|
||||||
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -230,6 +231,17 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@@ -511,6 +523,12 @@ version = "0.3.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.59"
|
version = "1.0.59"
|
||||||
@@ -529,6 +547,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -689,6 +737,12 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.86"
|
version = "0.2.86"
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
minifb = "0.24.0"
|
minifb = "0.24.0"
|
||||||
num = "0.4.0"
|
num = "0.4.0"
|
||||||
|
rand = "0.8.5"
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
|
|||||||
150
src/main.rs
150
src/main.rs
@@ -1,10 +1,11 @@
|
|||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
use std::f64::consts::PI;
|
use rand::Rng;
|
||||||
|
use std::f64::{consts::PI, INFINITY};
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use minifb::{Key, Window, WindowOptions};
|
use minifb::{Key, Window, WindowOptions};
|
||||||
use num::Complex;
|
use num::{Complex, Float};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
@@ -55,20 +56,24 @@ struct Mandlebrot {
|
|||||||
pub view_x: f64,
|
pub view_x: f64,
|
||||||
pub view_y: f64,
|
pub view_y: f64,
|
||||||
pub view_zoom: f64,
|
pub view_zoom: f64,
|
||||||
|
pub supersampling_range: f64,
|
||||||
|
pub supersampling_min_dist: f64,
|
||||||
pub max_iterations: u32,
|
pub max_iterations: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mandlebrot {
|
impl Mandlebrot {
|
||||||
fn new() -> Mandlebrot {
|
fn new() -> Mandlebrot {
|
||||||
let height: usize = 800;
|
let height: usize = 1800;
|
||||||
let width: usize = 800;
|
let width: usize = 1800;
|
||||||
Mandlebrot {
|
Mandlebrot {
|
||||||
view_width: width,
|
view_width: width,
|
||||||
view_height: height,
|
view_height: height,
|
||||||
view_x: 0.0,
|
view_x: -0.6,
|
||||||
view_y: 0.0,
|
view_y: 0.0,
|
||||||
view_zoom: 1.0,
|
view_zoom: 2.2,
|
||||||
max_iterations: 512,
|
supersampling_range: 4.0,
|
||||||
|
supersampling_min_dist: 0.5,
|
||||||
|
max_iterations: 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,19 +88,137 @@ impl Mandlebrot {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel(&self, x: u32, y: u32) -> Complex<f64> {
|
fn mandlebrot_sochastic_supersample(&self, x: u32, y: u32, limit: u32) -> Option<u32> {
|
||||||
|
// first we need to make the pisson disc of out sampling point and generate c for them
|
||||||
let cx = self.view_zoom * (x as f64 / self.view_width as f64 - 0.5) + self.view_x;
|
let cx = self.view_zoom * (x as f64 / self.view_width as f64 - 0.5) + self.view_x;
|
||||||
let cy = self.view_zoom * (y as f64 / self.view_height as f64 - 0.5) + self.view_y;
|
let cy = self.view_zoom * (y as f64 / self.view_height as f64 - 0.5) + self.view_y;
|
||||||
Complex { re: cx, im: cy }
|
|
||||||
|
// this is the fast bridson algorithm first outlined here:
|
||||||
|
// https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
|
||||||
|
let pisson_disc_sample = |cx: f64, cy: f64| -> Vec<Complex<f64>> {
|
||||||
|
let mut ret = Vec::<Complex<f64>>::new();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let cell_size = self.supersampling_min_dist / 1.41421356237; // sqrt of 2
|
||||||
|
let grid_size = (self.supersampling_range / cell_size).ceil();
|
||||||
|
|
||||||
|
let mut grid = Vec::<(f64, f64)>::with_capacity(
|
||||||
|
(self.supersampling_range * self.supersampling_range) as usize,
|
||||||
|
);
|
||||||
|
let mut proc = Vec::<(f64, f64)>::new(); // treat as a stack
|
||||||
|
|
||||||
|
let in_area = |p: (f64, f64)| -> bool {
|
||||||
|
p.0 > 0.0
|
||||||
|
&& p.0 < self.supersampling_range
|
||||||
|
&& p.1 > 0.0
|
||||||
|
&& p.1 < self.supersampling_range
|
||||||
|
};
|
||||||
|
|
||||||
|
let squared_distance = |a: (f64, f64), b: (f64, f64)| -> f64 {
|
||||||
|
let delta_x = a.0 - b.0;
|
||||||
|
let delta_y = a.1 - b.1;
|
||||||
|
delta_x * delta_x * delta_y * delta_y
|
||||||
|
};
|
||||||
|
|
||||||
|
let point_around = |p: (f64, f64)| -> (f64, f64) {
|
||||||
|
let radius =
|
||||||
|
self.supersampling_min_dist * (rng.gen_range(0.0..3.0) + 1.0f64).sqrt();
|
||||||
|
let angle = rng.gen_range(0.0..PI * 2.0);
|
||||||
|
(p.0 + angle.cos() * radius, p.1 + angle.sin() * radius)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut set = |p: (f64, f64)| {
|
||||||
|
let cell = ((p.0 / cell_size) as usize, (p.1 / cell_size) as usize);
|
||||||
|
grid[cell.1 * self.supersampling_range as usize + cell.0] = p;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut add = |p: (f64, f64)| {
|
||||||
|
let c = Complex { re: p.0, im: p.1 };
|
||||||
|
ret.push(c);
|
||||||
|
proc.push(p);
|
||||||
|
set(p);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut p_too_close = |p: (f64, f64)| -> bool {
|
||||||
|
let xi = (p.0 / cell_size).floor() as usize;
|
||||||
|
let yi = (p.1 / cell_size).floor() as usize;
|
||||||
|
|
||||||
|
if grid[yi * grid_size as usize + xi].0 != INFINITY {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let min_dist_sq = self.supersampling_min_dist * self.supersampling_min_dist;
|
||||||
|
let minx = (xi - 2).max(0);
|
||||||
|
let miny = (yi - 2).max(0);
|
||||||
|
let maxx = (xi + 2).min(grid_size as usize - 1);
|
||||||
|
let maxy = (yi + 2).min(grid_size as usize - 1);
|
||||||
|
|
||||||
|
for y in miny..=maxy {
|
||||||
|
for x in minx..=maxx {
|
||||||
|
let point = grid[y * grid_size as usize + x];
|
||||||
|
let exists = point.0 != INFINITY;
|
||||||
|
if exists && squared_distance(p, point) < min_dist_sq {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let start_p = (
|
||||||
|
rng.gen_range(0.0..self.supersampling_range),
|
||||||
|
rng.gen_range(0.0..self.supersampling_range),
|
||||||
|
);
|
||||||
|
add(start_p);
|
||||||
|
|
||||||
|
while !proc.is_empty() {
|
||||||
|
let point = proc.pop().unwrap(); // we can safely unwrap here
|
||||||
|
for i in 0..30 {
|
||||||
|
let p = point_around(point);
|
||||||
|
if in_area(p) && !p_too_close(p) {
|
||||||
|
add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
};
|
||||||
|
|
||||||
|
let samples = pisson_disc_sample(cx, cy);
|
||||||
|
let samples: Vec<Option<u32>> = samples
|
||||||
|
.iter()
|
||||||
|
.map(|c| -> Option<u32> {
|
||||||
|
let mut z = Complex { re: 0.0, im: 0.0 };
|
||||||
|
|
||||||
|
for i in 0..limit {
|
||||||
|
z = z * z + c;
|
||||||
|
if z.norm() > 2.0 {
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let summed_iterations: u32 = samples
|
||||||
|
.iter()
|
||||||
|
.map(|x| if x.is_some() { x.unwrap() } else { 0 })
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
Some(summed_iterations / samples.len() as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mandlebrot(&self, c: Complex<f64>, limit: u32) -> Option<(u32, Complex<f64>)> {
|
fn mandlebrot(&self, x: u32, y: u32, limit: u32) -> Option<u32> {
|
||||||
|
let cx = self.view_zoom * (x as f64 / self.view_width as f64 - 0.5) + self.view_x;
|
||||||
|
let cy = self.view_zoom * (y as f64 / self.view_height as f64 - 0.5) + self.view_y;
|
||||||
|
|
||||||
|
let c = Complex { re: cx, im: cy };
|
||||||
let mut z = Complex { re: 0.0, im: 0.0 };
|
let mut z = Complex { re: 0.0, im: 0.0 };
|
||||||
|
|
||||||
for i in 0..limit {
|
for i in 0..limit {
|
||||||
z = z * z + c;
|
z = z * z + c;
|
||||||
if z.norm() > 2.0 {
|
if z.norm() > 2.0 {
|
||||||
return Some((i, z));
|
return Some(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -107,10 +230,9 @@ impl Mandlebrot {
|
|||||||
(scaled_v, scaled_v, scaled_v)
|
(scaled_v, scaled_v, scaled_v)
|
||||||
};
|
};
|
||||||
|
|
||||||
let c = self.get_pixel(x, y);
|
match self.mandlebrot(x, y, self.max_iterations) {
|
||||||
match self.mandlebrot(c, self.max_iterations) {
|
|
||||||
None => 0,
|
None => 0,
|
||||||
Some((count, _z)) => {
|
Some(count) => {
|
||||||
let col = cyclic_shading(count, self.max_iterations);
|
let col = cyclic_shading(count, self.max_iterations);
|
||||||
(col.0 as u32) << 16 | (col.1 as u32) << 8 | col.2 as u32
|
(col.0 as u32) << 16 | (col.1 as u32) << 8 | col.2 as u32
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user