aboutsummaryrefslogtreecommitdiff
path: root/src/renderer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer.rs')
-rw-r--r--src/renderer.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/renderer.rs b/src/renderer.rs
new file mode 100644
index 0000000..468f4ff
--- /dev/null
+++ b/src/renderer.rs
@@ -0,0 +1,110 @@
+use cgmath::Vector3;
+use cgmath::prelude::*;
+use ncurses::addstr;
+use std::f32;
+
+use crate::Buffer;
+use crate::Camera;
+
+type Vector = Vector3<f32>;
+
+pub struct Renderer {
+ pub camera: Camera,
+ pub buffer: Buffer,
+}
+
+impl Renderer {
+ pub fn render(&self, sdf: &dyn Fn(Vector) -> f32) {
+ let (mut ray_dir, mut step_h, mut step_v) = self.camera.get_screen_iterator();
+
+ step_v /= self.buffer.height;
+ step_h /= self.buffer.width;
+
+ 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]);
+ }
+ ray_dir -= step_h * self.buffer.width;
+ addstr(&row);
+ }
+ }
+
+ pub fn ray_march(origin: Vector, direction: Vector, sdf: &dyn Fn(Vector) -> f32) -> Option<Vector> {
+ let threshold = 0.1;
+
+ let ray = direction.normalize();
+ let mut point = origin;
+ let mut dist = 0.0;
+ let mut count = 0;
+
+ while dist < 8.0 && count < 10 {
+ count += 1;
+ dist = sdf(point);
+ if dist.abs() < threshold {
+ return Some(point);
+ }
+ point += ray * dist;
+ }
+
+ return 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
+ )
+ }
+
+ pub fn diffuse_lighting(point: Vector, light: Vector, sdf: &dyn Fn(Vector) -> f32) -> f32 {
+ let mut res: f32 = 1.0;
+ let mut t = 0.1;
+ let k = 4.0;
+
+ while t < 1.0 {
+ let h = sdf(point - light * t);
+ if h < 0.001 {
+ return 0.00
+ }
+ res = res.min(k * h / t);
+ t += h;
+ }
+
+ return 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)
+ }
+
+ pub fn normal(point: Vector, sdf: &dyn Fn(Vector) -> f32) -> Vector {
+ let d = 0.001;
+
+ let dx = Vector::unit_x() * d;
+ let dy = Vector::unit_y() * d;
+ let dz = Vector::unit_z() * d;
+
+ let dist = sdf(point);
+
+ return (Vector {
+ x: (sdf(point + dx) - dist),
+ y: (sdf(point + dy) - dist),
+ z: (sdf(point + dz) - dist),
+ } / d).normalize()
+ }
+}