diff options
Diffstat (limited to 'src/renderer.rs')
-rw-r--r-- | src/renderer.rs | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/src/renderer.rs b/src/renderer.rs index 0c6c8d2..6db67e2 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,7 +1,9 @@ -use cgmath::Vector3; use cgmath::prelude::*; +use cgmath::Vector3; use ncurses::addstr; +use rayon::prelude::*; use std::f32; +use std::sync::Arc; use crate::Buffer; use crate::Camera; @@ -9,17 +11,16 @@ use crate::Object; type Vector = Vector3<f32>; -pub struct Renderer<'a> { - pub camera: Box<Camera>, - pub buffer: Box<Buffer>, - pub sdf: Box<dyn Fn(Vector, f32) -> f32 + 'a>, +pub struct Renderer { + pub camera: Camera, + pub buffer: Buffer, + pub sdf: Arc<dyn Fn(Vector3<f32>, f32) -> f32 + Send + Sync>, } -impl Renderer<'_> { - // TODO: figure out how the fuck it actually works - pub fn new(buffer: Box<Buffer>, camera: Box<Camera>, objects: Vec<Box<dyn Object>>) -> Self { +impl Renderer { + pub fn new(buffer: Buffer, camera: Camera, objects: Vec<Box<dyn Object>>) -> Self { let sdf = move |point: Vector3<f32>, time: f32| -> f32 { - let mut dist: f32 = 100000.0; + let mut dist = f32::MAX; for object in objects.iter() { dist = dist.min(object.sdf(point, time)); } @@ -29,41 +30,49 @@ impl Renderer<'_> { Self { buffer, camera, - sdf: Box::new(sdf) + sdf: Arc::new(sdf), } } pub fn render(&self, time: f32) { - let (mut ray_dir, mut step_h, mut step_v) = self.camera.get_screen_iterator(); + let mut iterator = self.camera.get_screen_iterator(); + iterator.set_buffer_size(&self.buffer); - let sdf = |point: Vector3<f32>| -> f32 { - (self.sdf)(point, time) - }; + let sdf = |point: Vector3<f32>| -> f32 { (self.sdf)(point, time) }; - step_v /= self.buffer.height; - step_h /= self.buffer.width; + let ray_dirs: Vec<Vector3<f32>> = iterator.collect(); + + // Ray march in parallel + let chars: Vec<char> = ray_dirs + .par_iter() + .map(|ray_dir| { + let collision = Self::ray_march(self.camera.position, *ray_dir, &sdf); + match collision { + Some(point) => Self::light_point(point, &sdf), + None => 0.0, + } + }) + .map(|brightness| { + self.buffer.palette + [((1.0 - brightness) * (self.buffer.palette.len() - 1) as f32) as usize] + }) + .collect(); for _i in 0..self.buffer.height as usize { - ray_dir += step_v; let mut row = "\n".to_string(); for _j in 0..self.buffer.width as usize { - ray_dir += step_h; - - let collision = Self::ray_march(self.camera.position, ray_dir, &sdf); - - let brightness = match collision { - Some(point) => Self::light_point(point, &sdf), - None => 0.0 - }; - - row.push(self.buffer.palette[((1.0 - brightness) * (self.buffer.palette.len() - 1) as f32) as usize]); + let character = chars[_i * self.buffer.width as usize + _j]; + row.push(character); } - ray_dir -= step_h * self.buffer.width; addstr(&row); } } - pub fn ray_march(origin: Vector, direction: Vector, sdf: &dyn Fn(Vector) -> f32) -> Option<Vector> { + pub fn ray_march( + origin: Vector, + direction: Vector, + sdf: &dyn Fn(Vector) -> f32, + ) -> Option<Vector> { let threshold = 0.1; let ray = direction.normalize(); @@ -80,16 +89,16 @@ impl Renderer<'_> { point += ray * dist; } - return None + None } pub fn light_point(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 { let light = Vector::new(1.0, 1.0, -1.0); let ambient = 0.1; - return ambient + (1.0 - ambient) * ( - Self::diffuse_lighting(point, light, sdf) * 0.7 + - Self::specular_lighting(point, light, sdf) * 0.3 - ) + ambient + + (1.0 - ambient) + * (Self::diffuse_lighting(point, light, sdf) * 0.7 + + Self::specular_lighting(point, light, sdf) * 0.3) } pub fn diffuse_lighting(point: Vector, light: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 { @@ -100,22 +109,22 @@ impl Renderer<'_> { while t < 1.0 { let h = sdf(point - light * t); if h < 0.001 { - return 0.00 + return 0.00; } res = res.min(k * h / t); t += h; } - return res + res } pub fn specular_lighting(point: Vector, light: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 { let normal = Self::normal(point, sdf); let dot = -(normal.dot(light)); - return dot.min(1.0).max(0.0) - } + dot.min(1.0).max(0.0) + } - pub fn normal(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> Vector { + pub fn normal(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> Vector { let d = 0.001; let dx = Vector::unit_x() * d; @@ -124,10 +133,11 @@ impl Renderer<'_> { let dist = sdf(point); - return (Vector { + (Vector { x: (sdf(point + dx) - dist), y: (sdf(point + dy) - dist), z: (sdf(point + dz) - dist), - } / d).normalize() + } / d) + .normalize() } } |