Add more abstraction.
Implement Sphere as its own module. Create HitableList that can hold multiple objects. Fixed shading problem in the process.
This commit is contained in:
parent
c16ba06a53
commit
15fe1e632c
46
rtiow/src/bin/tracer_multiple_spheres.rs
Normal file
46
rtiow/src/bin/tracer_multiple_spheres.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
extern crate rtiow;
|
||||||
|
|
||||||
|
use rtiow::hitable::Hit;
|
||||||
|
use rtiow::hitable_list::HitableList;
|
||||||
|
use rtiow::ray::Ray;
|
||||||
|
use rtiow::sphere::Sphere;
|
||||||
|
use rtiow::vec3::Vec3;
|
||||||
|
|
||||||
|
fn color(r: Ray, world: &Hit) -> Vec3 {
|
||||||
|
if let Some(rec) = world.hit(r, 0., std::f32::MAX) {
|
||||||
|
return (rec.normal + 1.) * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No hit, choose color from background.
|
||||||
|
let unit_direction = r.direction().unit_vector();
|
||||||
|
let t = 0.5 * (unit_direction.y + 1.);
|
||||||
|
Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
let nx = 200;
|
||||||
|
let ny = 100;
|
||||||
|
println!("P3\n{} {}\n255", nx, ny);
|
||||||
|
let lower_left_corner = Vec3::new(-2., -1., -1.);
|
||||||
|
let horizontal = Vec3::new(4., 0., 0.);
|
||||||
|
let vertical = Vec3::new(0., 2., 0.);
|
||||||
|
let origin: Vec3 = Default::default();
|
||||||
|
let objects = vec![
|
||||||
|
Sphere::new(Vec3::new(0., 0., -1.), 0.5),
|
||||||
|
Sphere::new(Vec3::new(0., -100.5, -1.), 100.),
|
||||||
|
];
|
||||||
|
let world = HitableList::new(objects.iter().map(|o| o).collect());
|
||||||
|
for j in (0..ny).rev() {
|
||||||
|
for i in 0..nx {
|
||||||
|
let u = i as f32 / nx as f32;
|
||||||
|
let v = j as f32 / ny as f32;
|
||||||
|
let r = Ray::new(origin, lower_left_corner + horizontal * u + vertical * v);
|
||||||
|
let col = color(r, &world);
|
||||||
|
let ir = (255.99 * col[0]) as u32;
|
||||||
|
let ig = (255.99 * col[1]) as u32;
|
||||||
|
let ib = (255.99 * col[2]) as u32;
|
||||||
|
println!("{} {} {}", ir, ig, ib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
13
rtiow/src/hitable.rs
Normal file
13
rtiow/src/hitable.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use ray::Ray;
|
||||||
|
use vec3::Vec3;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct HitRecord {
|
||||||
|
pub t: f32,
|
||||||
|
pub p: Vec3,
|
||||||
|
pub normal: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Hit {
|
||||||
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord>;
|
||||||
|
}
|
||||||
37
rtiow/src/hitable_list.rs
Normal file
37
rtiow/src/hitable_list.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use hitable::Hit;
|
||||||
|
use hitable::HitRecord;
|
||||||
|
use ray::Ray;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct HitableList<'a, H>
|
||||||
|
where
|
||||||
|
H: Hit + 'a,
|
||||||
|
{
|
||||||
|
list: Vec<&'a H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H> HitableList<'a, H>
|
||||||
|
where
|
||||||
|
H: Hit,
|
||||||
|
{
|
||||||
|
pub fn new(list: Vec<&'a H>) -> HitableList<H> {
|
||||||
|
HitableList { list }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H> Hit for HitableList<'a, H>
|
||||||
|
where
|
||||||
|
H: Hit,
|
||||||
|
{
|
||||||
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||||
|
let mut min_hit = None;
|
||||||
|
let mut closest_so_far = t_max;
|
||||||
|
for hitable in &self.list {
|
||||||
|
if let Some(h) = hitable.hit(r, t_min, closest_so_far) {
|
||||||
|
closest_so_far = h.t;
|
||||||
|
min_hit = Some(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
min_hit
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,5 @@
|
|||||||
|
pub mod hitable;
|
||||||
|
pub mod hitable_list;
|
||||||
pub mod ray;
|
pub mod ray;
|
||||||
|
pub mod sphere;
|
||||||
pub mod vec3;
|
pub mod vec3;
|
||||||
|
|||||||
48
rtiow/src/sphere.rs
Normal file
48
rtiow/src/sphere.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use hitable::Hit;
|
||||||
|
use hitable::HitRecord;
|
||||||
|
use ray::Ray;
|
||||||
|
use vec3::dot;
|
||||||
|
use vec3::Vec3;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub struct Sphere {
|
||||||
|
center: Vec3,
|
||||||
|
radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sphere {
|
||||||
|
pub fn new(center: Vec3, radius: f32) -> Sphere {
|
||||||
|
Sphere { center, radius }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hit for Sphere {
|
||||||
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||||
|
let oc = r.origin() - self.center;
|
||||||
|
let a = dot(r.direction(), r.direction());
|
||||||
|
let b = dot(oc, r.direction());
|
||||||
|
let c = dot(oc, oc) - self.radius * self.radius;
|
||||||
|
let discriminant = b * b - a * c;
|
||||||
|
if discriminant > 0. {
|
||||||
|
let temp = (-b - (b * b - a * c).sqrt()) / a;
|
||||||
|
if temp < t_max && temp > t_min {
|
||||||
|
let p = r.point_at_parameter(temp);
|
||||||
|
return Some(HitRecord {
|
||||||
|
t: temp,
|
||||||
|
p,
|
||||||
|
normal: (p - self.center) / self.radius,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let temp = (-b + (b * b - a * c).sqrt()) / a;
|
||||||
|
if temp < t_max && temp > t_min {
|
||||||
|
let p = r.point_at_parameter(temp);
|
||||||
|
return Some(HitRecord {
|
||||||
|
t: temp,
|
||||||
|
p,
|
||||||
|
normal: (p - self.center) / self.radius,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user