render percentage, new test scene but currently buggy

main
Codinget 4 years ago
parent f50a22ecff
commit 0f1195ba08
  1. 8
      src/consts.rs
  2. 18
      src/main.rs
  3. 6
      src/material.rs
  4. 32
      src/object/exclusion.rs
  5. 7
      src/object/intersection.rs
  6. 6
      src/object/mod.rs
  7. 2
      src/object/transform.rs
  8. 55
      src/structs/cam.rs

@ -4,8 +4,10 @@ pub const COLOR_CHANNELS: usize = 4;
pub const EPSILON: f64 = 1. / 1024.; pub const EPSILON: f64 = 1. / 1024.;
pub const LIGHT_EPSILON: f64 = 1. / 512.; pub const LIGHT_EPSILON: f64 = 1. / 512.;
pub const MAX_DIST: f64 = 16.; //pub const MAX_DIST: f64 = 16.;
pub const MAX_DIST: f64 = 32.;
pub const MAX_STEPS: u32 = 1024; pub const MAX_STEPS: u32 = 1024;
//pub const MAX_STEPS: u32 = u32::MAX;
pub const DIST_FIX_CORRECTION: f64 = 0.5; pub const DIST_FIX_CORRECTION: f64 = 0.5;
pub const DIST_CORRECTION: f64 = 3.; pub const DIST_CORRECTION: f64 = 3.;
@ -35,8 +37,10 @@ pub const RAYS_PER_PIXEL: usize = 500;
//pub const MAX_BOUNCES: u32 = 8; //pub const MAX_BOUNCES: u32 = 8;
pub const MAX_BOUNCES: u32 = 10; pub const MAX_BOUNCES: u32 = 10;
//pub const THREAD_COUNT: usize = 1;
pub const THREAD_COUNT: usize = 12; pub const THREAD_COUNT: usize = 12;
pub const SLICES_PER_THREAD: usize = 4; pub const SLICES_PER_THREAD: usize = 16;
pub const REPORT_STATUS: bool = true;
pub const UP: Vec3 = Y; pub const UP: Vec3 = Y;
pub const RIGHT: Vec3 = X; pub const RIGHT: Vec3 = X;

@ -9,6 +9,7 @@ use crate::consts::*;
use crate::structs::*; use crate::structs::*;
use crate::material::*; use crate::material::*;
use image::{ColorType, ImageFormat}; use image::{ColorType, ImageFormat};
use crate::light::Light;
fn default_cam() -> Cam { fn default_cam() -> Cam {
Cam::new_pointing(Y*3. - X*5., O, 0.5) Cam::new_pointing(Y*3. - X*5., O, 0.5)
@ -64,6 +65,23 @@ fn default_scene2() -> Scene {
Scene::new(Union::new(Union::new(sphere, Union::new(wall, backwall)), Union::new(light, mirror))) Scene::new(Union::new(Union::new(sphere, Union::new(wall, backwall)), Union::new(light, mirror)))
} }
fn default_scene3() -> Scene {
//TODO fix this scene
let s1 = WithMaterial::new(Sphere::new_xyz(4., 0., 0., 1.), WHITE);
let s2 = WithMaterial::new(Sphere::new_xyz(3., 1., 1., 0.5), GREEN);
let navion = WithMaterial::new(Plane::new_xyz(0., 1., -1., 3.), BLUE);
let backwall = WithMaterial::new(Plane::new_xyz(-1., -1., -0.5, 8.), RED);
let boiboite = Cuboid::new_xyz(4., 1.1, -1.1, 0.5, 0.275, 0.275);
let decal = AffineTransform::new_translate(boiboite, Vec3::new(-0.25, 0., 0.5));
let nope = Exclusion::new(s1, Sphere::new_xyz(3.75, 0.75, 0.75, 1.));
let walls = Union::new(navion, backwall);
let spheres = Union::new(AffineTransform::new_linear(nope, scale(0.75)), s2);
let scene = Union::new(spheres, Union::new(walls, decal));
let light = WithMaterial::new(Plane::new_xyz(0., -1., 0., 8.), BRIGHT_AF_LIGHTSOURCE);
let scene = WithLight::new_one(scene, Light::new(Y*3.-X*5., ColorVec::new([2., 3., 4., 0.])));
Scene::new(Union::new(scene, light))
}
fn main() { fn main() {
// get scene and camera // get scene and camera
let scene = default_scene2(); let scene = default_scene2();

@ -71,6 +71,12 @@ pub const STRONG_LIGHTSOURCE: Material = Material::new_from_diagonal(
Stop Stop
); );
pub const BRIGHT_AF_LIGHTSOURCE: Material = Material::new_from_diagonal(
ColorVec::new([25., 25., 25., 0.]),
COLOR_ZERO,
Stop
);
pub const UV_LIGHTSOURCE: Material = Material::new_from_diagonal( pub const UV_LIGHTSOURCE: Material = Material::new_from_diagonal(
ColorVec::new_one(3), ColorVec::new_one(3),
ColorVec::new([0.25, 0.25, 0.25, 1.]), ColorVec::new([0.25, 0.25, 0.25, 1.]),

@ -0,0 +1,32 @@
use crate::object::Obj;
use crate::light::Light;
use crate::structs::Vec3;
use std::vec;
use crate::material::Material;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Exclusion<A: Obj, B: Obj> {
a: A,
b: B
}
impl<A: Obj, B: Obj> Exclusion<A, B> {
pub fn new(a: A, b: B) -> Exclusion<A, B> {
Exclusion { a, b }
}
}
impl<A: Obj, B: Obj> Obj for Exclusion<A, B> {
fn distance_to(&self, point: Vec3) -> f64 {
f64::max(self.a.distance_to(point), -self.b.distance_to(point))
}
fn material_at(&self, point: Vec3) -> Material {
self.a.material_at(point)
}
fn get_lights(&self) -> vec::Vec<Light> {
self.a.get_lights()
}
fn node_count(&self) -> u32 {
self.a.node_count() + self.b.node_count() + 1
}
}

@ -20,13 +20,6 @@ impl<A: Obj, B: Obj> Obj for Intersection<A, B> {
fn distance_to(&self, point: Vec3) -> f64 { fn distance_to(&self, point: Vec3) -> f64 {
f64::max(self.a.distance_to(point), self.b.distance_to(point)) f64::max(self.a.distance_to(point), self.b.distance_to(point))
} }
fn normal_at(&self, point: Vec3) -> Vec3 {
if self.a.distance_to(point) > self.b.distance_to(point) {
self.a.normal_at(point)
} else {
self.b.normal_at(point)
}
}
fn material_at(&self, point: Vec3) -> Material { fn material_at(&self, point: Vec3) -> Material {
if self.a.distance_to(point) > self.b.distance_to(point) { if self.a.distance_to(point) > self.b.distance_to(point) {
self.a.material_at(point) self.a.material_at(point)

@ -9,6 +9,7 @@ mod sphere;
mod plane; mod plane;
mod union; mod union;
mod intersection; mod intersection;
mod exclusion;
mod cuboid; mod cuboid;
mod cylinder; mod cylinder;
mod torus; mod torus;
@ -36,7 +37,9 @@ pub trait Obj: Send + Sync {
fn get_lights(&self) -> Vec<Light> { fn get_lights(&self) -> Vec<Light> {
Vec::new() Vec::new()
} }
fn node_count(&self) -> u32 { 1 } fn node_count(&self) -> u32 {
1
}
} }
impl<T: Obj> Obj for &T { impl<T: Obj> Obj for &T {
@ -61,6 +64,7 @@ pub use sphere::Sphere;
pub use plane::Plane; pub use plane::Plane;
pub use union::Union; pub use union::Union;
pub use intersection::Intersection; pub use intersection::Intersection;
pub use exclusion::Exclusion;
pub use cuboid::Cuboid; pub use cuboid::Cuboid;
pub use cylinder::Cylinder; pub use cylinder::Cylinder;
pub use torus::Torus; pub use torus::Torus;

@ -63,7 +63,7 @@ impl<T: Obj + Clone> Obj for AffineTransform<T> {
self.obj.distance_to(self.apply_rev(point)) self.obj.distance_to(self.apply_rev(point))
} }
fn normal_at(&self, point: Vec3) -> Vec3 { fn normal_at(&self, point: Vec3) -> Vec3 {
self.apply_fwd(self.obj.normal_at(self.apply_rev(point))) self.apply_fwd(self.obj.normal_at(self.apply_rev(point))).unit()
} }
fn material_at(&self, point: Vec3) -> Material { fn material_at(&self, point: Vec3) -> Material {
self.obj.material_at(self.apply_rev(point)) self.obj.material_at(self.apply_rev(point))

@ -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();
dir = (u*x + v*y + w*z).unit();
} else {
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.;

Loading…
Cancel
Save