|
|
@ -7,6 +7,7 @@ use std::f64::consts::PI; |
|
|
|
use rand::prelude::*; |
|
|
|
use rand::prelude::*; |
|
|
|
use crossbeam_channel::unbounded; |
|
|
|
use crossbeam_channel::unbounded; |
|
|
|
use std::ops::{Mul, Add, Sub}; |
|
|
|
use std::ops::{Mul, Add, Sub}; |
|
|
|
|
|
|
|
use std::io::Write; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)] |
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)] |
|
|
|
pub struct Cam { |
|
|
|
pub struct Cam { |
|
|
@ -99,10 +100,10 @@ fn shoot_ray_at<T: Obj>(scene: &T, pos: Vec3, dest: Vec3) -> bool { |
|
|
|
let point = ray.point(dist); |
|
|
|
let point = ray.point(dist); |
|
|
|
let sd = scene.distance_to(point); |
|
|
|
let sd = scene.distance_to(point); |
|
|
|
let dd = dest.distance_to(point); |
|
|
|
let dd = dest.distance_to(point); |
|
|
|
if sd < 0. { |
|
|
|
if sd <= 0. { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if dd < sd { |
|
|
|
if dd <= sd { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
dist += if sd < EPSILON { EPSILON } else { sd }; |
|
|
|
dist += if sd < EPSILON { EPSILON } else { sd }; |
|
|
@ -121,6 +122,12 @@ impl Cam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn render_singlethreaded<T: Obj>(&self, scene: &T) -> Image { |
|
|
|
pub fn render_singlethreaded<T: Obj>(&self, scene: &T) -> Image { |
|
|
|
|
|
|
|
let mut stderr = std::io::stderr(); |
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
stderr.write_all(format!("Rendering... 0/{} rows (0.00%)", IMG_HEIGHT).as_bytes()).unwrap(); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let lights = scene.get_lights(); |
|
|
|
let lights = scene.get_lights(); |
|
|
|
let mut pixels = [0; IMG_BYTE_SIZE]; |
|
|
|
let mut pixels = [0; IMG_BYTE_SIZE]; |
|
|
|
for y in 0..IMG_HEIGHT { |
|
|
|
for y in 0..IMG_HEIGHT { |
|
|
@ -128,7 +135,18 @@ impl Cam { |
|
|
|
let field_pos = (x + y*IMG_WIDTH) * 3; |
|
|
|
let field_pos = (x + y*IMG_WIDTH) * 3; |
|
|
|
self.render_single(scene, &lights, x, y, &mut pixels[field_pos..(field_pos+3)]); |
|
|
|
self.render_single(scene, &lights, x, y, &mut pixels[field_pos..(field_pos+3)]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
stderr.write_all(format!("\x1b[1K\x1b[GRendering... {}/{} rows ({:.2}%)", y+1, IMG_HEIGHT, (y+1) as f64/IMG_HEIGHT as f64).as_bytes()); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
stderr.write_all(format!("\x1b[1K\x1b[GRendering... Done\n").as_bytes()); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pixels |
|
|
|
pixels |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -176,6 +194,7 @@ impl Cam { |
|
|
|
drop(data_tx); |
|
|
|
drop(data_tx); |
|
|
|
|
|
|
|
|
|
|
|
// send the slice data
|
|
|
|
// send the slice data
|
|
|
|
|
|
|
|
let mut total_slices = 0u32; |
|
|
|
let mut y = 0; |
|
|
|
let mut y = 0; |
|
|
|
while y < IMG_HEIGHT { |
|
|
|
while y < IMG_HEIGHT { |
|
|
|
let mut x = 0; |
|
|
|
let mut x = 0; |
|
|
@ -184,12 +203,23 @@ impl Cam { |
|
|
|
let h = usize::min(slice_height, IMG_HEIGHT - y); |
|
|
|
let h = usize::min(slice_height, IMG_HEIGHT - y); |
|
|
|
slice_tx.send(Slice { x, y, w, h }).unwrap(); |
|
|
|
slice_tx.send(Slice { x, y, w, h }).unwrap(); |
|
|
|
x += slice_width; |
|
|
|
x += slice_width; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
total_slices += 1; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
y += slice_height; |
|
|
|
y += slice_height; |
|
|
|
} |
|
|
|
} |
|
|
|
drop(slice_tx); |
|
|
|
drop(slice_tx); |
|
|
|
|
|
|
|
|
|
|
|
// merge stuff as we get it
|
|
|
|
// merge stuff as we get it
|
|
|
|
|
|
|
|
let mut stderr = std::io::stderr(); |
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
stderr.write_all(format!("Rendering... 0/{} slices (0.00%), 0.00% pixels", total_slices).as_bytes()).unwrap(); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
let mut rendered_slices = 0u32; |
|
|
|
|
|
|
|
let mut rendered_pixels = 0u64; |
|
|
|
for (slice, data) in data_rx { |
|
|
|
for (slice, data) in data_rx { |
|
|
|
let data = data.as_slice(); |
|
|
|
let data = data.as_slice(); |
|
|
|
for sy in 0..slice.h { |
|
|
|
for sy in 0..slice.h { |
|
|
@ -204,6 +234,19 @@ impl Cam { |
|
|
|
pixels[pi + 2] = data[si + 2]; |
|
|
|
pixels[pi + 2] = data[si + 2]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
rendered_slices += 1; |
|
|
|
|
|
|
|
rendered_pixels += (slice.w*slice.h) as u64; |
|
|
|
|
|
|
|
let pct_slices = rendered_slices as f64 / total_slices as f64 * 100.; |
|
|
|
|
|
|
|
let pct_pixels = rendered_pixels as f64 / (IMG_WIDTH * IMG_HEIGHT) as f64 * 100.; |
|
|
|
|
|
|
|
stderr.write_all(format!("\x1b[1K\x1b[GRendering... {}/{} slices ({:.02}%), {:.02}% pixels", rendered_slices, total_slices, pct_slices, pct_pixels).as_bytes()).unwrap(); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if REPORT_STATUS { |
|
|
|
|
|
|
|
stderr.write_all(format!("\x1b[1K\x1b[GRendering... Done\n").as_bytes()); |
|
|
|
|
|
|
|
stderr.flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
}).unwrap(); |
|
|
|
}).unwrap(); |
|
|
|
|
|
|
|
|
|
|
@ -269,7 +312,7 @@ impl Cam { |
|
|
|
match hit { |
|
|
|
match hit { |
|
|
|
Some(hit) => { |
|
|
|
Some(hit) => { |
|
|
|
i += 1; |
|
|
|
i += 1; |
|
|
|
pos = hit.pos - dir * EPSILON; |
|
|
|
pos = hit.pos + (hit.normal - dir) * EPSILON; |
|
|
|
match hit.material.surface() { |
|
|
|
match hit.material.surface() { |
|
|
|
SurfaceType::Stop => break, |
|
|
|
SurfaceType::Stop => break, |
|
|
|
SurfaceType::Diffuse => { |
|
|
|
SurfaceType::Diffuse => { |
|
|
@ -281,11 +324,7 @@ impl Cam { |
|
|
|
let x = r1.cos()*r2.sqrt(); |
|
|
|
let x = r1.cos()*r2.sqrt(); |
|
|
|
let y = r1.sin()*r2.sqrt(); |
|
|
|
let y = r1.sin()*r2.sqrt(); |
|
|
|
let z = (1.-r2).sqrt(); |
|
|
|
let z = (1.-r2).sqrt(); |
|
|
|
if w.x().abs() < 0.5 { |
|
|
|
|
|
|
|
dir = (u*x + v*y + w*z).unit(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
dir = (u*x + v*y + w*z).unit(); |
|
|
|
dir = (u*x + v*y + w*z).unit(); |
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
SurfaceType::Reflective => { |
|
|
|
SurfaceType::Reflective => { |
|
|
|
dir = dir - hit.normal * (hit.normal * dir) * 2.; |
|
|
|
dir = dir - hit.normal * (hit.normal * dir) * 2.; |
|
|
|