rtiow: add blox with gloxy edges.

Fixed bug in kdtree that this uncovered.
Marked Hit and it's dependencies as needing to implement the Debug
trait.
This commit is contained in:
Bill Thiede 2022-09-17 16:45:29 -07:00
parent b432e9a6dd
commit 4066bf4b85
25 changed files with 338 additions and 10 deletions

View File

@ -9,6 +9,7 @@ use crate::{
ray::Ray,
};
#[derive(Debug)]
enum BVHNode {
Leaf(Box<dyn Hit>),
Branch {
@ -178,6 +179,7 @@ impl Hit for BVHNode {
}
}
#[derive(Debug)]
pub struct BVH {
root: BVHNode,
}

View File

@ -11,6 +11,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct ConstantMedium<H, T>
where
H: Hit,

View File

@ -11,6 +11,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct Cuboid {
p_min: Vec3,
p_max: Vec3,
@ -21,6 +22,9 @@ impl Cuboid {
// This clippy doesn't work right with Arc.
#[allow(clippy::needless_pass_by_value)]
pub fn new(p_min: Vec3, p_max: Vec3, material: Arc<dyn Material>) -> Cuboid {
assert!(p_min.x <= p_max.x);
assert!(p_min.y <= p_max.y);
assert!(p_min.z <= p_max.z);
Cuboid {
p_min,
p_max,

View File

@ -4,6 +4,7 @@ use crate::{
ray::Ray,
};
#[derive(Debug)]
pub struct FlipNormals<H>
where
H: Hit,

View File

@ -0,0 +1,142 @@
use std::sync::Arc;
use crate::{
aabb::AABB,
cuboid::Cuboid,
flip_normals::FlipNormals,
hitable::{Hit, HitRecord},
hitable_list::HitableList,
material::Material,
ray::Ray,
rect::{XYRect, XZRect, YZRect},
vec3::Vec3,
};
#[derive(Debug)]
pub struct Glowybox {
p_min: Vec3,
p_max: Vec3,
main: Cuboid,
edges: [Cuboid; 12],
}
impl Glowybox {
// This clippy doesn't work right with Arc.
#[allow(clippy::needless_pass_by_value)]
pub fn new(
p_min: Vec3,
p_max: Vec3,
edge_thickness: f32,
main_material: Arc<dyn Material>,
edge_material: Arc<dyn Material>,
) -> Glowybox {
assert!(p_min.x < p_max.x);
assert!(p_min.y < p_max.y);
assert!(p_min.z < p_max.z);
let main = Cuboid::new(p_min, p_max, main_material);
// Top edges
let ht = edge_thickness / 2.;
let edges = [
// Top edges
Cuboid::new(
[p_min.x - ht, p_max.y - ht, p_min.z - ht].into(),
[p_min.x + ht, p_max.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_min.x - ht, p_max.y - ht, p_min.z - ht].into(),
[p_max.x + ht, p_max.y + ht, p_min.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_max.x - ht, p_max.y - ht, p_min.z - ht].into(),
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_min.x - ht, p_max.y - ht, p_max.z - ht].into(),
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
// Bottom edges
Cuboid::new(
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
[p_min.x + ht, p_min.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
[p_max.x + ht, p_min.y + ht, p_min.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_max.x - ht, p_min.y - ht, p_min.z - ht].into(),
[p_max.x + ht, p_min.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_min.x - ht, p_min.y - ht, p_max.z - ht].into(),
[p_max.x + ht, p_min.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
// Middle edges
Cuboid::new(
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
[p_min.x + ht, p_max.y + ht, p_min.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_min.x - ht, p_min.y - ht, p_max.z - ht].into(),
[p_min.x + ht, p_max.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_max.x - ht, p_min.y - ht, p_min.z - ht].into(),
[p_max.x + ht, p_max.y + ht, p_min.z + ht].into(),
Arc::clone(&edge_material),
),
Cuboid::new(
[p_max.x - ht, p_min.y - ht, p_max.z - ht].into(),
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
Arc::clone(&edge_material),
),
];
let p_min = [p_min.x - ht, p_min.y - ht, p_min.z - ht].into();
let p_max = [p_max.x + ht, p_max.y + ht, p_max.z + ht].into();
Glowybox {
p_min,
p_max,
main,
edges,
}
}
}
impl Hit for Glowybox {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let mut edge_hit = None;
for edge in &self.edges {
if let Some(hit) = edge.hit(r, t_min, t_max) {
edge_hit = Some(hit);
break;
}
}
let main_hit = self.main.hit(r, t_min, t_max);
match (edge_hit, main_hit) {
(Some(ehit), Some(mhit)) => {
if mhit.t < ehit.t {
Some(mhit)
} else {
Some(ehit)
}
}
(Some(ehit), None) => Some(ehit),
(None, Some(mhit)) => Some(mhit),
_ => None,
}
}
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
Some(AABB::new(self.p_min, self.p_max))
}
}

View File

@ -1,7 +1,8 @@
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};
use crate::{aabb::AABB, material::Material, ray::Ray, vec3::Vec3};
#[derive(Debug)]
pub struct HitRecord<'m> {
pub t: f32,
pub uv: (f32, f32),
@ -10,7 +11,7 @@ pub struct HitRecord<'m> {
pub material: &'m dyn Material,
}
pub trait Hit: Send + Sync {
pub trait Hit: Send + Sync + Debug {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord>;
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB>;
}
@ -23,3 +24,12 @@ impl Hit for Arc<dyn Hit> {
(**self).bounding_box(t_min, t_max)
}
}
impl Hit for Box<dyn Hit> {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
(**self).hit(r, t_min, t_max)
}
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
(**self).bounding_box(t_min, t_max)
}
}

View File

@ -7,7 +7,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Default)]
#[derive(Debug, Default)]
pub struct HitableList {
list: Vec<Box<dyn Hit>>,
}

View File

@ -5,9 +5,11 @@ use log::info;
use crate::{
aabb::{surrounding_box, AABB},
hitable::{Hit, HitRecord},
hitable_list::HitableList,
ray::Ray,
};
#[derive(Debug)]
pub enum KDTree {
Leaf(Box<dyn Hit>),
Branch {
@ -102,6 +104,14 @@ impl KDTree {
}),
_ => panic!("Unreachable"),
};
info!("left_half {:?}", left_half);
info!("right_half {:?}", right_half);
if left_half.is_empty() {
return KDTree::Leaf(Box::new(HitableList::new(right_half)));
};
if right_half.is_empty() {
return KDTree::Leaf(Box::new(HitableList::new(left_half)));
};
KDTree::Branch {
left: Box::new(KDTree::new(left_half, t_min, t_max)),
right: Box::new(KDTree::new(right_half, t_min, t_max)),

View File

@ -4,6 +4,7 @@ pub mod camera;
pub mod constant_medium;
pub mod cuboid;
pub mod flip_normals;
pub mod glowybox;
pub mod hitable;
pub mod hitable_list;
pub mod human;

View File

@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};
use rand::{self, Rng};
@ -20,14 +20,14 @@ fn random_in_unit_sphere() -> Vec3 {
}
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct ScatterResponse {
pub scattered: Ray,
pub attenutation: Vec3,
pub reflected: bool,
}
pub trait Material: Send + Sync {
pub trait Material: Send + Sync + Debug {
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse;
fn emitted(&self, _u: f32, _v: f32, _p: Vec3) -> Vec3 {
Vec3::new(0., 0., 0.)
@ -52,6 +52,7 @@ impl Material for Box<dyn Material> {
}
}
#[derive(Debug)]
pub struct Isotropic<T>
where
T: Texture,
@ -82,6 +83,7 @@ where
}
}
#[derive(Debug)]
pub struct Lambertian<T>
where
T: Texture,
@ -113,6 +115,7 @@ where
}
}
#[derive(Debug)]
pub struct Metal {
albedo: Vec3,
fuzzy: f32,
@ -167,6 +170,7 @@ fn schlick(cosine: f32, ref_idx: f32) -> f32 {
r0 + (1. - r0) * (1. - cosine).powf(5.)
}
#[derive(Debug)]
pub struct Dielectric {
ref_idx: f32,
}
@ -213,6 +217,7 @@ impl Material for Dielectric {
}
}
#[derive(Debug)]
pub struct DiffuseLight<T>
where
T: Texture,

View File

@ -7,6 +7,7 @@ use crate::{
vec3::{dot, Vec3},
};
#[derive(Debug)]
pub struct MovingSphere<M>
where
M: Material,

View File

@ -5,6 +5,7 @@ use rand;
use crate::{noise::NoiseSource, vec3::Vec3};
const NOISE_SIZE: usize = 128;
#[derive(Debug)]
pub struct Lode {
// Using fixed array causes stack overflow.
noise: Vec<Vec<Vec<f32>>>, //[[[f32; NOISE_SIZE]; NOISE_SIZE]; NOISE_SIZE],

View File

@ -1,13 +1,13 @@
pub mod lode;
pub mod perlin;
use std::f32::consts::PI;
use std::{f32::consts::PI, fmt::Debug};
use serde_derive::Deserialize;
use crate::vec3::Vec3;
pub trait NoiseSource: Send + Sync {
pub trait NoiseSource: Send + Sync + Debug {
/// value returns noise on the interval [0., 1.).
fn value(&self, p: Vec3) -> f32;

View File

@ -8,6 +8,7 @@ use crate::{
vec3::{dot, Vec3},
};
#[derive(Debug)]
pub struct Perlin {
ran_vec: Vec<Vec3>,
perm_x: Vec<usize>,

View File

@ -8,6 +8,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct XYRect<M>
where
M: Material,
@ -69,6 +70,7 @@ where
}
}
#[derive(Debug)]
pub struct XZRect<M>
where
M: Material,
@ -130,6 +132,7 @@ where
}
}
#[derive(Debug)]
pub struct YZRect<M>
where
M: Material,

View File

@ -42,6 +42,7 @@ pub enum Model {
PerlinDebug,
Spheramid,
Test,
Tron,
Tutorial,
}
@ -58,6 +59,7 @@ impl Model {
Model::PerlinDebug => scenes::perlin_debug::new(opt),
Model::Spheramid => scenes::spheramid::new(opt),
Model::Test => scenes::test::new(opt),
Model::Tron => scenes::tron::new(opt),
Model::Tutorial => scenes::tutorial::new(opt),
}
}
@ -86,6 +88,7 @@ impl str::FromStr for Model {
"perlin_debug" => Ok(Model::PerlinDebug),
"spheramid" => Ok(Model::Spheramid),
"test" => Ok(Model::Test),
"tron" => Ok(Model::Tron),
"tutorial" => Ok(Model::Tutorial),
_ => Err(ModelParseError(s.to_owned())),
}
@ -105,6 +108,7 @@ impl std::string::ToString for Model {
Model::PerlinDebug => "perlin_debug".to_string(),
Model::Spheramid => "spheramid".to_string(),
Model::Test => "test".to_string(),
Model::Tron => "tron".to_string(),
Model::Tutorial => "tutorial".to_string(),
}
}

View File

@ -7,6 +7,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct RotateY<H>
where
H: Hit,

View File

@ -8,4 +8,5 @@ pub mod mandelbrot;
pub mod perlin_debug;
pub mod spheramid;
pub mod test;
pub mod tron;
pub mod tutorial;

View File

@ -0,0 +1,135 @@
use std::sync::Arc;
use image;
use log::info;
use rand;
use crate::{
camera::Camera,
cuboid::Cuboid,
glowybox::Glowybox,
hitable::Hit,
hitable_list::HitableList,
kdtree::KDTree,
material::{DiffuseLight, Lambertian},
noise::{perlin::Perlin, NoiseType},
rect::{XYRect, XZRect, YZRect},
renderer::{Opt, Scene},
sphere::Sphere,
texture::{ConstantTexture, ImageTexture, NoiseTexture},
vec3::Vec3,
};
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(20., 20., 20.);
let lookat = Vec3::new(0., 1., 0.);
let dist_to_focus = 10.0;
let aperture = 0.0;
let time_min = 0.;
let time_max = 1.;
let camera = Camera::new(
lookfrom,
lookat,
Vec3::new(0., 1., 0.),
20.,
opt.width as f32 / opt.height as f32,
aperture,
dist_to_focus,
time_min,
time_max,
);
let rng = &mut rand::thread_rng();
let ground_color = if opt.use_accel {
ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
} else {
ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4))
};
let world_image_bytes = include_bytes!("../../images/world.jpg");
let it = ImageTexture::new(image::load_from_memory(world_image_bytes).unwrap().to_rgb());
let noise_source = Perlin::new(rng);
let noise_type = NoiseType::Scale(10.);
let lights: Vec<Box<dyn Hit>> = vec![
Box::new(XZRect::new(
-100.,
100.,
-100.,
1000.,
60.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 1.))),
)),
Box::new(YZRect::new(
1.,
3.,
-1.,
1.,
4.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 0., 4.))),
)),
Box::new(YZRect::new(
1.,
3.,
-1.,
1.,
-4.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 0.))),
)),
Box::new(XZRect::new(
-1.,
1.,
-1.,
1.,
6.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 4., 0.))),
)),
Box::new(XYRect::new(
-1.,
1.,
1.,
3.,
-4.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 0., 4.))),
)),
Box::new(XYRect::new(
-1.,
1.,
1.,
3.,
4.,
DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 4.))),
)),
];
let mut objects: Vec<Box<dyn Hit>> = vec![
// Earth sized sphere
Box::new(Sphere::new(
Vec3::new(0., -1010., 0.),
1000.,
Lambertian::new(ground_color),
// Lambertian::new(NoiseTexture::new(noise_source, noise_type)),
)),
Box::new(Glowybox::new(
[-4., -4., -4.].into(),
[4., 4., 4.].into(),
0.01,
Arc::new(Lambertian::new(ConstantTexture::new([0., 0., 0.]))),
Arc::new(DiffuseLight::new(ConstantTexture::new([100., 0., 0.]))),
)),
];
objects.extend(lights);
info!("objects {:?}", objects);
let world: Box<dyn Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max))
} else {
Box::new(HitableList::new(objects))
};
Scene {
camera,
world,
subsamples: opt.subsamples,
num_threads: opt.num_threads,
width: opt.width,
height: opt.height,
..Default::default()
}
}

View File

@ -8,6 +8,7 @@ use crate::{
vec3::{dot, Vec3},
};
#[derive(Debug)]
pub struct Sphere<M>
where
M: Material,

View File

@ -1,5 +1,6 @@
use crate::{texture::Texture, vec3::Vec3};
#[derive(Debug)]
pub struct CheckerTexture<T>
where
T: Texture,

View File

@ -3,6 +3,7 @@ use rand::{self, Rng};
use crate::{texture::Texture, vec3::Vec3};
#[derive(Debug)]
pub struct Mandelbrot {
palette: Vec<Vec3>,
}

View File

@ -9,11 +9,11 @@ pub use crate::texture::{
mandelbrot::Mandelbrot, noise::NoiseTexture,
};
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};
use crate::vec3::Vec3;
pub trait Texture: Send + Sync {
pub trait Texture: Send + Sync + Debug {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3;
}

View File

@ -4,6 +4,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct NoiseTexture<N>
where
N: NoiseSource,

View File

@ -5,6 +5,7 @@ use crate::{
vec3::Vec3,
};
#[derive(Debug)]
pub struct Translate<H>
where
H: Hit,