diff --git a/src/main.rs b/src/main.rs index 8b5b7e7..635fe97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use crate::image_texture::ImageTexture; use crate::noise::NoiseTexture; use crate::perlin::Perlin; use crate::texture::CheckerTexture; +use crate::xy_rect::XyRect; mod vec3; mod ray; @@ -28,6 +29,7 @@ mod texture; mod perlin; mod noise; mod image_texture; +mod xy_rect; // Image const ASPECT_RATIO: f64 = 3.0 / 2.0; @@ -42,6 +44,57 @@ struct Scene { pub background: Color } +fn simple_light() -> Scene { + let mut world:HittableList = Vec::new(); + + let noise = NoiseTexture { noise: Perlin::new(), scale: 4.0 }; + let noise_material = Arc::new(Material::Lambertian(Lambertian::textured(Arc::new(noise)))); + world.push(Arc::new(Sphere { + center: Point3::new(0.0, -1000.0, 0.0), + radius: 1000.0, + material: Arc::clone(&noise_material) + })); + world.push(Arc::new(Sphere { + center: Point3::new(0.0, 2.0, 0.0), + radius: 2.0, + material: noise_material + })); + + + let difflight = Material::DiffuseLight( + // Brighter than 1.0/1.0/1.0 so it can light things + DiffuseLight::from(Color::new(4.0, 4.0, 4.0))); + world.push(Arc::new(XyRect { + x0: 3.0, + x1: 5.0, + y0: 1.0, + y1: 3.0, + k: -2.0, + material: Arc::new(difflight) + })); + + let look_from = Point3::new(26.0, 3.0, 6.0); + let look_at = Point3::new(0.0, 2.0, 0.0); + let focus_dist = 2.0; + + let cam = Camera::new( + look_from, + look_at, + Vec3::new(0.0, 1.0, 0.0), + ASPECT_RATIO, + 20.0, + 0.0, + focus_dist, + 0.0, + 1.0); + + Scene { + world, + cam, + background: Color::default() + } +} + fn sun() -> Scene { let mut world:HittableList = Vec::new(); let earth_material = Arc::new( @@ -283,12 +336,13 @@ fn random_scene() -> Scene { fn main() { // World - let scene: u8 = 3; + let scene: u8 = 4; let scene_setup = match scene { 0 => two_spheres(), 1 => two_perlin_spheres(), 2 => earth(), 3 => sun(), + 4 => simple_light(), _ => random_scene(), }; diff --git a/src/xy_rect.rs b/src/xy_rect.rs new file mode 100644 index 0000000..4c5564f --- /dev/null +++ b/src/xy_rect.rs @@ -0,0 +1,48 @@ +use std::sync::Arc; +use crate::hittable::{HitRecord, Hittable}; +use crate::{Aabb, Material, Point3, Ray, Vec3}; + +pub struct XyRect { + pub x0: f64, + pub x1: f64, + pub y0: f64, + pub y1: f64, + pub k: f64, + pub material: Arc +} + +impl Hittable for XyRect { + fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { + let t = (self.k - ray.origin().z()) / ray.direction().z(); + if t < t_min || t > t_max { + return None; + } + let x = ray.origin().x() + t * ray.direction().x(); + let y = ray.origin().y() + t * ray.direction().y(); + if x < self.x0 || x > self.x1 || y < self.y0 || y > self.y1 { + return None; + } + let normal = Vec3::new(0.0, 0.0, 1.0); + let dot = ray.direction().dot(&normal); + let front_face = dot < 0.0; + let normal = if front_face { normal } else { -normal }; + Some(HitRecord { + point: ray.at(t), + normal, + t, + u: (x-self.x0)/(self.x1-self.x0), + v: (y-self.y0)/(self.y1-self.y0), + front_face, + material: &self.material + }) + } + + fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { + // The bounding box must have non-zero width in each dimension, so pad the Z + // dimension a small amount. + Some(Aabb { + minimum: Point3::new(self.x0, self.y0, self.k-0.0001), + maximum: Point3::new(self.x1, self.y1, self.k+0.0001), + }) + } +}