rtiow: Many changes

Add debugging hit DebugHit.
Move some color helpers from mandelbrot to colors mod.
Implement Texture trait for [f32;3]
This commit is contained in:
2023-02-13 20:57:10 -08:00
parent deb46acb5a
commit e19ec20c7b
9 changed files with 294 additions and 77 deletions

View File

@@ -0,0 +1,46 @@
use rand::{self, Rng};
use crate::vec3::Vec3;
// HSV values in [0..1]
// returns [r, g, b] values from 0 to 255
//From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
pub fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 {
let h_i = (h * 6.) as i32;
let f = h * 6. - h_i as f32;
let p = v * (1. - s);
let q = v * (1. - f * s);
let t = v * (1. - (1. - f) * s);
match h_i {
0 => Vec3::new(v, t, p),
1 => Vec3::new(q, v, p),
2 => Vec3::new(p, v, t),
3 => Vec3::new(p, q, v),
4 => Vec3::new(t, p, v),
5 => Vec3::new(v, p, q),
_ => panic!("Unknown H value {}", h_i),
}
}
pub fn generate_rainbow(num: usize) -> Vec<Vec3> {
(0..num)
.map(|n| {
let h = n as f32 / num as f32;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}
pub fn generate_palette(num: usize) -> Vec<Vec3> {
let mut rng = rand::thread_rng();
let mut random = || rng.gen();
// use golden ratio
let golden_ratio_conjugate = 0.618_034;
let mut h = random();
(0..num)
.map(|_| {
h += golden_ratio_conjugate;
h %= 1.0;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}

View File

@@ -0,0 +1,46 @@
use crate::{
aabb::AABB,
hitable::{Hit, HitRecord},
material::Lambertian,
ray::Ray,
texture::{self, ConstantTexture},
vec3::Vec3,
};
#[derive(Debug)]
pub struct DebugHit<H>
where
H: Hit,
{
hitable: H,
material: Lambertian<[f32; 3]>,
}
impl<H> DebugHit<H>
where
H: Hit,
{
pub fn new(hitable: H) -> DebugHit<H>
where {
DebugHit {
hitable,
material: Lambertian::new([0.2, 0.2, 0.2]),
}
}
}
impl<H> Hit for DebugHit<H>
where
H: Hit,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
if let Some(hit) = self.hitable.hit(r, t_min, t_max) {
return Some(HitRecord { t: hit.t, ..hit });
}
None
}
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
self.hitable.bounding_box(t_min, t_max)
}
}

View File

@@ -2,8 +2,10 @@ pub mod aabb;
pub mod bvh;
pub mod bvh_triangles;
pub mod camera;
pub mod colors;
pub mod constant_medium;
pub mod cuboid;
pub mod debug_hit;
pub mod flip_normals;
pub mod glowybox;
pub mod hitable;

View File

@@ -1,15 +1,21 @@
use std::io::{BufReader, Cursor};
use std::{
f32::consts::PI,
io::{BufReader, Cursor},
iter::Inspect,
};
use stl::STL;
use crate::{
bvh_triangles::BVHTriangles,
camera::Camera,
colors::generate_rainbow,
hitable::Hit,
hitable_list::HitableList,
kdtree::KDTree,
material::{Dielectric, Lambertian},
material::{Dielectric, Lambertian, Metal},
renderer::{Opt, Scene},
rotate::RotateY,
scale::Scale,
sphere::Sphere,
texture::{ConstantTexture, EnvMap},
@@ -18,8 +24,8 @@ use crate::{
};
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(0., 40., -100.);
let lookat = Vec3::new(0., 10., 0.);
let lookfrom = Vec3::new(0., 80., 80.);
let lookat = Vec3::new(0., 0., 0.);
let dist_to_focus = 10.0;
let aperture = 0.0;
let time_min = 0.;
@@ -35,6 +41,10 @@ pub fn new(opt: &Opt) -> Scene {
time_min,
time_max,
);
//let dragon_material = Dielectric::new(1.5);
let dragon_material = Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.0);
//let dragon_material = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 1.0, 0.2)));
let ground_color = if opt.use_accel {
ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
} else {
@@ -42,46 +52,51 @@ pub fn new(opt: &Opt) -> Scene {
};
let stl_cube = STL::parse(
BufReader::new(Cursor::new(include_bytes!(
"../../stls/stanford_dragon-lowres.stl" //"../../stls/stanford_dragon.stl"
))),
BufReader::new(Cursor::new(include_bytes!("../../stls/dragon.stl"))),
//BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))),
false,
)
.expect("failed to parse cube");
let _light_size = 50.;
let _light_height = 200.;
let objects: Vec<Box<dyn Hit>> = vec![
// Light from above - white
let sphere_radius = 5.;
let circle_radius = 40.;
let num_spheres = 16;
let palette = generate_rainbow(num_spheres);
let spheres: Vec<Box<dyn Hit>> = (0..num_spheres)
.map(|i| (i, i as f32, num_spheres as f32))
.map(|(idx, idx_f, n)| (idx, idx_f * 2. * PI / n))
.map(|(idx, rad)| -> Box<dyn Hit> {
let x = circle_radius * rad.cos();
let y = 4. * sphere_radius;
let z = circle_radius * rad.sin();
let c = palette[idx];
Box::new(Sphere::new(
[x, y, z],
sphere_radius,
Lambertian::new(ConstantTexture::new(c)),
))
})
.collect();
let mut objects: Vec<Box<dyn Hit>> = vec![
Box::new(Sphere::new(
Vec3::new(0., 0.1, -0.5),
0.1,
Lambertian::new([0., 1., 1.]),
)),
// Earth sized sphere
Box::new(Sphere::new(
Vec3::new(0., -10000., 0.),
10000.,
Lambertian::new(ground_color),
)),
// Blue sphere
Box::new(Sphere::new(
Vec3::new(0., 20., 40.),
20.,
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))),
)),
Box::new(Sphere::new(
Vec3::new(40., 20., 40.),
20.,
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))),
)),
Box::new(Sphere::new(
Vec3::new(-40., 20., 40.),
20.,
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)),
//Box::new(Sphere::new( Vec3::new(0., -10000., 0.), 10000., Lambertian::new(ground_color),)),
// STL Mesh
Box::new(Translate::new(
Scale::new(BVHTriangles::new(&stl_cube, Dielectric::new(1.5)), 250.),
[0., -10., 0.],
)),
Box::new(crate::debug_hit::DebugHit::new(RotateY::new(
Translate::new(
Scale::new(BVHTriangles::new(&stl_cube, dragon_material), 250.),
[0., -10., 0.],
),
180.,
))),
];
objects.extend(spheres);
let world: Box<dyn Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max))
} else {

View File

@@ -16,6 +16,7 @@ use crate::{
renderer::{Opt, Scene},
sphere::Sphere,
texture::{ConstantTexture, EnvMap},
translate::Translate,
vec3::Vec3,
};
@@ -47,7 +48,7 @@ pub fn new(opt: &Opt) -> Scene {
let metal = Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2);
let red = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2)));
let box_material = glass;
//let box_material = glass;
let _ = glass;
let _ = metal;
let _ = red;
@@ -65,6 +66,11 @@ pub fn new(opt: &Opt) -> Scene {
10000.,
Lambertian::new(ground_color),
)),
Box::new(Sphere::new(
Vec3::new(0., 20., -40.),
10.,
Lambertian::new(ConstantTexture::new(Vec3::new(1., 0.2, 1.))),
)),
// Blue sphere
Box::new(Sphere::new(
Vec3::new(0., 20., 40.),
@@ -84,11 +90,15 @@ pub fn new(opt: &Opt) -> Scene {
Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)),
// STL Mesh
Box::new(BVHTriangles::new(&stl_cube, box_material.clone())),
Box::new(Translate::new(
BVHTriangles::new(&stl_cube, glass),
[0., 10., 0.],
)),
//Box::new(BVHTriangles::new(&stl_cube, box_material.clone())),
Box::new(Cuboid::new(
[-20., 0., 0.].into(),
[0., 20., 20.].into(),
Arc::new(box_material),
Arc::new(red),
)),
];
let world: Box<dyn Hit> = if opt.use_accel {

View File

@@ -1,48 +1,12 @@
#![allow(clippy::many_single_char_names)]
use rand::{self, Rng};
use crate::{texture::Texture, vec3::Vec3};
use crate::{colors::generate_palette, texture::Texture, vec3::Vec3};
#[derive(Debug)]
pub struct Mandelbrot {
palette: Vec<Vec3>,
}
// HSV values in [0..1]
// returns [r, g, b] values from 0 to 255
//From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 {
let h_i = (h * 6.) as i32;
let f = h * 6. - h_i as f32;
let p = v * (1. - s);
let q = v * (1. - f * s);
let t = v * (1. - (1. - f) * s);
match h_i {
0 => Vec3::new(v, t, p),
1 => Vec3::new(q, v, p),
2 => Vec3::new(p, v, t),
3 => Vec3::new(p, q, v),
4 => Vec3::new(t, p, v),
5 => Vec3::new(v, p, q),
_ => panic!("Unknown H value {}", h_i),
}
}
fn generate_palette(num: usize) -> Vec<Vec3> {
let mut rng = rand::thread_rng();
let mut random = || rng.gen();
// use golden ratio
let golden_ratio_conjugate = 0.618_034;
let mut h = random();
(0..num)
.map(|_| {
h += golden_ratio_conjugate;
h %= 1.0;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}
impl Default for Mandelbrot {
fn default() -> Self {
Mandelbrot {

View File

@@ -29,6 +29,12 @@ impl Texture for Box<dyn Texture> {
}
}
impl Texture for [f32; 3] {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(*self).into()
}
}
#[cfg(test)]
mod test {
use super::*;