diff options
33 files changed, 1604 insertions, 383 deletions
diff --git a/src/camera.rs b/src/camera.rs index 55bf387..52c2011 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,6 +1,6 @@ use crate::ray::Ray; -use crate::vec3::{Point3, Vec3}; use crate::util::degrees_to_radians; +use crate::vec3::{Point3, Vec3}; pub struct Camera { origin: Point3, @@ -16,7 +16,17 @@ pub struct Camera { } impl Camera { - pub fn new(lookfrom: Point3, lookat: Point3, vup: Vec3, vfov: f64, aspect_ratio: f64, aperture: f64, focus_dist: f64, time_start: f64, time_end: f64) -> Camera { + pub fn new( + lookfrom: Point3, + lookat: Point3, + vup: Vec3, + vfov: f64, + aspect_ratio: f64, + aperture: f64, + focus_dist: f64, + time_start: f64, + time_end: f64, + ) -> Camera { let theta = degrees_to_radians(vfov); let h = (theta / 2.0).tan(); let viewport_height = 2.0 * h; @@ -30,10 +40,7 @@ impl Camera { let horizontal = focus_dist * viewport_width * &u; let vertical = focus_dist * viewport_height * &v; Camera { - lower_left_corner: &origin - - &horizontal / 2.0 - - &vertical / 2.0 - - focus_dist * &w, + lower_left_corner: &origin - &horizontal / 2.0 - &vertical / 2.0 - focus_dist * &w, origin, horizontal, vertical, @@ -51,7 +58,9 @@ impl Camera { let offset = &self.u * rd.x + &self.v * rd.y; Ray { origin: &self.origin + &offset, - direction: &self.lower_left_corner + s * &self.horizontal + t * &self.vertical - &self.origin - &offset, + direction: &self.lower_left_corner + s * &self.horizontal + t * &self.vertical + - &self.origin + - &offset, time: self.time_start + (self.time_end - self.time_start) * rand::random::<f64>(), } } diff --git a/src/display/image.rs b/src/display/image.rs index 77d8c83..4b25cb2 100644 --- a/src/display/image.rs +++ b/src/display/image.rs @@ -1,7 +1,7 @@ use std::io::Write; -use crate::vec3::Color; use crate::display::{Display, Pixel}; +use crate::vec3::Color; pub struct Image { width: usize, @@ -39,7 +39,9 @@ impl Display for Image { } fn maybe_write(&self, output: &mut impl Write) { - output.write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height)).unwrap(); + output + .write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height)) + .unwrap(); for y in (0..self.height).rev() { for x in 0..self.width { let pixel = self.data.get((y * self.width) + x).unwrap(); diff --git a/src/display/pixelflut.rs b/src/display/pixelflut.rs index 3a62f8d..9b71c8e 100644 --- a/src/display/pixelflut.rs +++ b/src/display/pixelflut.rs @@ -1,8 +1,8 @@ use std::io::Write; -use std::net::{TcpStream}; +use std::net::TcpStream; +use crate::display::{Display, Pixel}; use crate::vec3::Color; -use crate::display::{Display, Pixel}; pub struct Pixelflut { socket: TcpStream, @@ -54,15 +54,22 @@ impl Display for Pixelflut { for x in 0..self.width { let pixel = self.data.get((y * self.width) + x).unwrap(); let scale = 1.0 / pixel.sample_count as f64; - let mut r = (pixel.color.x * scale).sqrt(); - let mut g = (pixel.color.y * scale).sqrt(); - let mut b = (pixel.color.z * scale).sqrt(); - self.socket.write(format!("PX {} {} {:02x}{:02x}{:02x}\n", - self.x + x, - self.y + self.height - y, - (256.0 * r.clamp(0.0, 0.999)) as u32, - (256.0 * g.clamp(0.0, 0.999)) as u32, - (256.0 * b.clamp(0.0, 0.999)) as u32).as_bytes()); + let r = (pixel.color.x * scale).sqrt(); + let g = (pixel.color.y * scale).sqrt(); + let b = (pixel.color.z * scale).sqrt(); + self.socket + .write( + format!( + "PX {} {} {:02x}{:02x}{:02x}\n", + self.x + x, + self.y + self.height - y, + (256.0 * r.clamp(0.0, 0.999)) as u32, + (256.0 * g.clamp(0.0, 0.999)) as u32, + (256.0 * b.clamp(0.0, 0.999)) as u32 + ) + .as_bytes(), + ) + .unwrap(); } } } diff --git a/src/hittable/bvh_node.rs b/src/hittable/bvh_node.rs index d215bc3..405ab5b 100644 --- a/src/hittable/bvh_node.rs +++ b/src/hittable/bvh_node.rs @@ -2,7 +2,7 @@ use std::{cmp, sync::Arc}; use rand::seq::SliceRandom; -use crate::hittable::{HitRecord, Hittable, AABB, hittable_list::HittableList}; +use crate::hittable::{hittable_list::HittableList, HitRecord, Hittable, AABB}; use crate::ray::Ray; pub struct BVHNode { @@ -20,34 +20,72 @@ enum Axis { impl BVHNode { pub fn new(hittable_list: &HittableList, time_start: f64, time_end: f64) -> BVHNode { - Self::from_objects(&hittable_list.objects, 0, hittable_list.objects.len(), time_start, time_end) + Self::from_objects( + &hittable_list.objects, + 0, + hittable_list.objects.len(), + time_start, + time_end, + ) } - fn from_objects(src_objects: &Vec<Arc<dyn Hittable>>, start: usize, end: usize, time_start: f64, time_end: f64) -> BVHNode { + fn from_objects( + src_objects: &Vec<Arc<dyn Hittable>>, + start: usize, + end: usize, + time_start: f64, + time_end: f64, + ) -> BVHNode { let mut objects = src_objects.clone(); let comparator = [ - |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::X), - |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::Y), - |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::Z), - ].choose(&mut rand::thread_rng()).unwrap(); + |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| { + Self::box_compare(a.clone(), b.clone(), Axis::X) + }, + |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| { + Self::box_compare(a.clone(), b.clone(), Axis::Y) + }, + |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| { + Self::box_compare(a.clone(), b.clone(), Axis::Z) + }, + ] + .choose(&mut rand::thread_rng()) + .unwrap(); let object_span = end - start; let (left, right) = match object_span { - 1 => (objects.get(start).unwrap().clone(), objects.get(start).unwrap().clone()), + 1 => ( + objects.get(start).unwrap().clone(), + objects.get(start).unwrap().clone(), + ), 2 => match comparator(objects.get(start).unwrap(), objects.get(start + 1).unwrap()) { - cmp::Ordering::Less => (objects.get(start).unwrap().clone(), objects.get(start + 1).unwrap().clone()), - _ => (objects.get(start + 1).unwrap().clone(), objects.get(start).unwrap().clone()), - } + cmp::Ordering::Less => ( + objects.get(start).unwrap().clone(), + objects.get(start + 1).unwrap().clone(), + ), + _ => ( + objects.get(start + 1).unwrap().clone(), + objects.get(start).unwrap().clone(), + ), + }, _ => { objects[start..end].sort_by(comparator); let mid = start + object_span / 2; - (Arc::new(BVHNode::from_objects(&objects, start, mid, time_start, time_end)) as Arc<dyn Hittable>, - Arc::new(BVHNode::from_objects(&objects, mid, end, time_start, time_end)) as Arc<dyn Hittable>) - + ( + Arc::new(BVHNode::from_objects( + &objects, start, mid, time_start, time_end, + )) as Arc<dyn Hittable>, + Arc::new(BVHNode::from_objects( + &objects, mid, end, time_start, time_end, + )) as Arc<dyn Hittable>, + ) } }; - let box_left = left.bounding_box(time_start, time_end).expect("No bounding box in bvh_node constructor!"); - let box_right = right.bounding_box(time_start, time_end).expect("No bounding box in bvh_node constructor!"); + let box_left = left + .bounding_box(time_start, time_end) + .expect("No bounding box in bvh_node constructor!"); + let box_right = right + .bounding_box(time_start, time_end) + .expect("No bounding box in bvh_node constructor!"); BVHNode { left, @@ -56,19 +94,28 @@ impl BVHNode { } } - fn box_compare (a: Arc<dyn Hittable>, b: Arc<dyn Hittable>, axis: Axis) -> cmp::Ordering { - let box_a = a.bounding_box(0.0, 0.0).expect("No bounding box in bvh_node constructor!"); - let box_b = b.bounding_box(0.0, 0.0).expect("No bounding box in bvh_node constructor!"); + fn box_compare(a: Arc<dyn Hittable>, b: Arc<dyn Hittable>, axis: Axis) -> cmp::Ordering { + let box_a = a + .bounding_box(0.0, 0.0) + .expect("No bounding box in bvh_node constructor!"); + let box_b = b + .bounding_box(0.0, 0.0) + .expect("No bounding box in bvh_node constructor!"); // TODO: total_cmp is unstable :( - box_a.minimum.get(axis as usize).unwrap().partial_cmp(box_b.minimum.get(axis as usize).unwrap()).unwrap() + box_a + .minimum + .get(axis as usize) + .unwrap() + .partial_cmp(box_b.minimum.get(axis as usize).unwrap()) + .unwrap() } } impl Hittable for BVHNode { fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> { if !self.aabb.hit(ray, t_min, t_max) { - return None + return None; } let hit_left = self.left.hit(ray, t_min, t_max); let hit_right_threshold = if let Some(hit_record_left) = &hit_left { diff --git a/src/hittable/constant_medium.rs b/src/hittable/constant_medium.rs index 36ac2ff..50bddc6 100644 --- a/src/hittable/constant_medium.rs +++ b/src/hittable/constant_medium.rs @@ -1,6 +1,12 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::{Isotropic, Material}, ray::Ray, texture::Texture, vec3::{Vec3, Point3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::{Isotropic, Material}, + ray::Ray, + texture::Texture, + vec3::Vec3, +}; pub struct ConstantMedium { boundary: Arc<dyn Hittable>, @@ -13,7 +19,7 @@ impl ConstantMedium { Self { boundary, phase_function: Arc::new(Isotropic::from_texture(texture)), - neg_inv_density: -1.0/density, + neg_inv_density: -1.0 / density, } } } @@ -52,10 +58,14 @@ impl Hittable for ConstantMedium { p: ray.at(t), t, material: Some(self.phase_function.clone()), - normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 }, // arbitrary + normal: Vec3 { + x: 1.0, + y: 0.0, + z: 0.0, + }, // arbitrary front_face: true, // arbitrary - u: 0.0, // arbitrary - v: 0.0, // arbitrary + u: 0.0, // arbitrary + v: 0.0, // arbitrary }) } diff --git a/src/hittable/hittable_box.rs b/src/hittable/hittable_box.rs index 7b95cc7..9631635 100644 --- a/src/hittable/hittable_box.rs +++ b/src/hittable/hittable_box.rs @@ -1,6 +1,14 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB, hittable_list::HittableList, xy_rect::XYRect, xz_rect::XZRect, yz_rect::YZRect}, material::Material, ray::Ray, vec3::Point3}; +use crate::{ + hittable::{ + hittable_list::HittableList, xy_rect::XYRect, xz_rect::XZRect, yz_rect::YZRect, HitRecord, + Hittable, AABB, + }, + material::Material, + ray::Ray, + vec3::Point3, +}; pub struct HittableBox { min: Point3, @@ -12,20 +20,58 @@ impl HittableBox { pub fn new(min: Point3, max: Point3, material: Arc<dyn Material>) -> Self { let mut sides = HittableList::new(); - sides.add(Arc::new(XYRect { material: material.clone(), x0: min.x, x1: max.x, y0: min.y, y1: max.y, k: max.z })); - sides.add(Arc::new(XYRect { material: material.clone(), x0: min.x, x1: max.x, y0: min.y, y1: max.y, k: min.z })); + sides.add(Arc::new(XYRect { + material: material.clone(), + x0: min.x, + x1: max.x, + y0: min.y, + y1: max.y, + k: max.z, + })); + sides.add(Arc::new(XYRect { + material: material.clone(), + x0: min.x, + x1: max.x, + y0: min.y, + y1: max.y, + k: min.z, + })); - sides.add(Arc::new(XZRect { material: material.clone(), x0: min.x, x1: max.x, z0: min.z, z1: max.z, k: max.y })); - sides.add(Arc::new(XZRect { material: material.clone(), x0: min.x, x1: max.x, z0: min.z, z1: max.z, k: min.y })); + sides.add(Arc::new(XZRect { + material: material.clone(), + x0: min.x, + x1: max.x, + z0: min.z, + z1: max.z, + k: max.y, + })); + sides.add(Arc::new(XZRect { + material: material.clone(), + x0: min.x, + x1: max.x, + z0: min.z, + z1: max.z, + k: min.y, + })); - sides.add(Arc::new(YZRect { material: material.clone(), y0: min.y, y1: max.y, z0: min.z, z1: max.z, k: max.x })); - sides.add(Arc::new(YZRect { material: material.clone(), y0: min.y, y1: max.y, z0: min.z, z1: max.z, k: min.x })); + sides.add(Arc::new(YZRect { + material: material.clone(), + y0: min.y, + y1: max.y, + z0: min.z, + z1: max.z, + k: max.x, + })); + sides.add(Arc::new(YZRect { + material: material.clone(), + y0: min.y, + y1: max.y, + z0: min.z, + z1: max.z, + k: min.x, + })); - Self { - min, - max, - sides, - } + Self { min, max, sides } } } @@ -35,6 +81,9 @@ impl Hittable for HittableBox { } fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> { - Some(AABB { minimum: self.min.clone(), maximum: self.max.clone() }) + Some(AABB { + minimum: self.min.clone(), + maximum: self.max.clone(), + }) } } diff --git a/src/hittable/instance/moving.rs b/src/hittable/instance/moving.rs index 418fdbb..062af86 100644 --- a/src/hittable/instance/moving.rs +++ b/src/hittable/instance/moving.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use crate::{ray::Ray, vec3::Vec3}; use crate::hittable::{HitRecord, Hittable, AABB}; +use crate::{ray::Ray, vec3::Vec3}; pub struct Moving { pub hittable: Arc<dyn Hittable>, @@ -13,13 +13,19 @@ pub struct Moving { impl Moving { fn offset_at(&self, time: f64) -> Vec3 { - &self.offset_start + ((time - self.time_start) / (self.time_end - self.time_start)) * (&self.offset_end - &self.offset_start) + &self.offset_start + + ((time - self.time_start) / (self.time_end - self.time_start)) + * (&self.offset_end - &self.offset_start) } } impl Hittable for Moving { fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> { - let moved_ray = Ray { origin: &ray.origin - &self.offset_at(ray.time), direction: ray.direction.clone(), time: ray.time }; + let moved_ray = Ray { + origin: &ray.origin - &self.offset_at(ray.time), + direction: ray.direction.clone(), + time: ray.time, + }; let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?; hit_record.p += self.offset_at(ray.time).clone(); let normal = hit_record.normal.clone(); @@ -29,12 +35,15 @@ impl Hittable for Moving { fn bounding_box(&self, time_start: f64, time_end: f64) -> Option<AABB> { let output_box = self.hittable.bounding_box(time_start, time_end)?; - Some(AABB { - minimum: &output_box.minimum + &self.offset_at(time_start), - maximum: &output_box.maximum + &self.offset_at(time_start), - }.surrounding_box(&AABB { - minimum: &output_box.minimum + &self.offset_at(time_end), - maximum: &output_box.maximum + &self.offset_at(time_end), - })) + Some( + AABB { + minimum: &output_box.minimum + &self.offset_at(time_start), + maximum: &output_box.maximum + &self.offset_at(time_start), + } + .surrounding_box(&AABB { + minimum: &output_box.minimum + &self.offset_at(time_end), + maximum: &output_box.maximum + &self.offset_at(time_end), + }), + ) } } diff --git a/src/hittable/instance/rotate_x.rs b/src/hittable/instance/rotate_x.rs index 4ebc04d..0e09223 100644 --- a/src/hittable/instance/rotate_x.rs +++ b/src/hittable/instance/rotate_x.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + ray::Ray, + util::degrees_to_radians, + vec3::{Point3, Vec3}, +}; pub struct RotateX { hittable: Arc<dyn Hittable>, @@ -14,11 +19,25 @@ impl RotateX { let radians = degrees_to_radians(angle); let sin_theta = radians.sin(); let cos_theta = radians.cos(); - match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious. - None => Self { hittable, sin_theta, cos_theta, aabb: None }, + match hittable.bounding_box(0.0, 1.0) { + // TODO: passing in 0.0 and 1.0 for time seems suspicious. + None => Self { + hittable, + sin_theta, + cos_theta, + aabb: None, + }, Some(aabb) => { - let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY }; - let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY }; + let mut min = Point3 { + x: f64::INFINITY, + y: f64::INFINITY, + z: f64::INFINITY, + }; + let mut max = Point3 { + x: -f64::INFINITY, + y: -f64::INFINITY, + z: -f64::INFINITY, + }; for i in 0..2 { for j in 0..2 { for k in 0..2 { @@ -28,15 +47,24 @@ impl RotateX { let new_y = cos_theta * y + sin_theta * y; let new_z = -sin_theta * y + cos_theta * z; - let tester = Vec3 { y: new_y, x, z: new_z }; + let tester = Vec3 { + y: new_y, + x, + z: new_z, + }; for c in 0..3 { - *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap()); - *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap()); + *min.get_mut(c).unwrap() = + min.get(c).unwrap().min(*tester.get(c).unwrap()); + *max.get_mut(c).unwrap() = + max.get(c).unwrap().max(*tester.get(c).unwrap()); } } } } - let aabb = AABB { minimum: min, maximum: max }; + let aabb = AABB { + minimum: min, + maximum: max, + }; Self { hittable, @@ -56,17 +84,21 @@ impl Hittable for RotateX { origin.y = self.cos_theta * ray.origin.y - self.sin_theta * ray.origin.z; origin.z = self.sin_theta * ray.origin.y + self.cos_theta * ray.origin.z; - + direction.y = self.cos_theta * ray.direction.y - self.sin_theta * ray.direction.z; direction.z = self.sin_theta * ray.direction.y + self.cos_theta * ray.direction.z; - let rotated_ray = Ray { origin, direction, time: ray.time }; + let rotated_ray = Ray { + origin, + direction, + time: ray.time, + }; let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?; let mut p = hit_record.p.clone(); let mut normal = hit_record.normal.clone(); - p.y = self.cos_theta * hit_record.p.y+ self.sin_theta * hit_record.p.z; + p.y = self.cos_theta * hit_record.p.y + self.sin_theta * hit_record.p.z; p.z = -self.sin_theta * hit_record.p.y + self.cos_theta * hit_record.p.z; normal.y = self.cos_theta * hit_record.normal.y + self.sin_theta * hit_record.normal.z; diff --git a/src/hittable/instance/rotate_y.rs b/src/hittable/instance/rotate_y.rs index 8611616..8f34c09 100644 --- a/src/hittable/instance/rotate_y.rs +++ b/src/hittable/instance/rotate_y.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + ray::Ray, + util::degrees_to_radians, + vec3::{Point3, Vec3}, +}; pub struct RotateY { hittable: Arc<dyn Hittable>, @@ -14,11 +19,25 @@ impl RotateY { let radians = degrees_to_radians(angle); let sin_theta = radians.sin(); let cos_theta = radians.cos(); - match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious. - None => Self { hittable, sin_theta, cos_theta, aabb: None }, + match hittable.bounding_box(0.0, 1.0) { + // TODO: passing in 0.0 and 1.0 for time seems suspicious. + None => Self { + hittable, + sin_theta, + cos_theta, + aabb: None, + }, Some(aabb) => { - let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY }; - let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY }; + let mut min = Point3 { + x: f64::INFINITY, + y: f64::INFINITY, + z: f64::INFINITY, + }; + let mut max = Point3 { + x: -f64::INFINITY, + y: -f64::INFINITY, + z: -f64::INFINITY, + }; for i in 0..2 { for j in 0..2 { for k in 0..2 { @@ -28,15 +47,24 @@ impl RotateY { let new_x = cos_theta * x + sin_theta * z; let new_z = -sin_theta * x + cos_theta * z; - let tester = Vec3 { x: new_x, y, z: new_z }; + let tester = Vec3 { + x: new_x, + y, + z: new_z, + }; for c in 0..3 { - *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap()); - *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap()); + *min.get_mut(c).unwrap() = + min.get(c).unwrap().min(*tester.get(c).unwrap()); + *max.get_mut(c).unwrap() = + max.get(c).unwrap().max(*tester.get(c).unwrap()); } } } } - let aabb = AABB { minimum: min, maximum: max }; + let aabb = AABB { + minimum: min, + maximum: max, + }; Self { hittable, @@ -56,11 +84,15 @@ impl Hittable for RotateY { origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.z; origin.z = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.z; - + direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.z; direction.z = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.z; - let rotated_ray = Ray { origin, direction, time: ray.time }; + let rotated_ray = Ray { + origin, + direction, + time: ray.time, + }; let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?; let mut p = hit_record.p.clone(); diff --git a/src/hittable/instance/rotate_z.rs b/src/hittable/instance/rotate_z.rs index 119baca..38601ce 100644 --- a/src/hittable/instance/rotate_z.rs +++ b/src/hittable/instance/rotate_z.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + ray::Ray, + util::degrees_to_radians, + vec3::{Point3, Vec3}, +}; pub struct RotateZ { hittable: Arc<dyn Hittable>, @@ -14,11 +19,25 @@ impl RotateZ { let radians = degrees_to_radians(angle); let sin_theta = radians.sin(); let cos_theta = radians.cos(); - match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious. - None => Self { hittable, sin_theta, cos_theta, aabb: None }, + match hittable.bounding_box(0.0, 1.0) { + // TODO: passing in 0.0 and 1.0 for time seems suspicious. + None => Self { + hittable, + sin_theta, + cos_theta, + aabb: None, + }, Some(aabb) => { - let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY }; - let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY }; + let mut min = Point3 { + x: f64::INFINITY, + y: f64::INFINITY, + z: f64::INFINITY, + }; + let mut max = Point3 { + x: -f64::INFINITY, + y: -f64::INFINITY, + z: -f64::INFINITY, + }; for i in 0..2 { for j in 0..2 { for k in 0..2 { @@ -28,15 +47,24 @@ impl RotateZ { let new_x = cos_theta * x + sin_theta * y; let new_y = -sin_theta * x + cos_theta * y; - let tester = Vec3 { x: new_x, z, y: new_y }; + let tester = Vec3 { + x: new_x, + z, + y: new_y, + }; for c in 0..3 { - *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap()); - *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap()); + *min.get_mut(c).unwrap() = + min.get(c).unwrap().min(*tester.get(c).unwrap()); + *max.get_mut(c).unwrap() = + max.get(c).unwrap().max(*tester.get(c).unwrap()); } } } } - let aabb = AABB { minimum: min, maximum: max }; + let aabb = AABB { + minimum: min, + maximum: max, + }; Self { hittable, @@ -56,11 +84,15 @@ impl Hittable for RotateZ { origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.y; origin.y = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.y; - + direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.y; direction.y = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.y; - let rotated_ray = Ray { origin, direction, time: ray.time }; + let rotated_ray = Ray { + origin, + direction, + time: ray.time, + }; let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?; let mut p = hit_record.p.clone(); diff --git a/src/hittable/instance/translate.rs b/src/hittable/instance/translate.rs index a9c8162..8478bd4 100644 --- a/src/hittable/instance/translate.rs +++ b/src/hittable/instance/translate.rs @@ -1,6 +1,10 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, vec3::Vec3}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + ray::Ray, + vec3::Vec3, +}; pub struct Translate { pub hittable: Arc<dyn Hittable>, @@ -9,7 +13,11 @@ pub struct Translate { impl Hittable for Translate { fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> { - let moved_ray = Ray { origin: &ray.origin - &self.offset, direction: ray.direction.clone(), time: ray.time }; + let moved_ray = Ray { + origin: &ray.origin - &self.offset, + direction: ray.direction.clone(), + time: ray.time, + }; let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?; hit_record.p += self.offset.clone(); let normal = hit_record.normal.clone(); diff --git a/src/hittable/mod.rs b/src/hittable/mod.rs index e888c71..b2b06f0 100644 --- a/src/hittable/mod.rs +++ b/src/hittable/mod.rs @@ -1,5 +1,5 @@ -pub mod instance; mod bvh_node; +pub mod instance; pub use bvh_node::BVHNode; mod constant_medium; pub use constant_medium::ConstantMedium; @@ -23,9 +23,9 @@ mod aabb; use std::sync::Arc; +use crate::material::Material; use crate::ray::Ray; use crate::vec3::{Point3, Vec3}; -use crate::material::Material; use aabb::AABB; #[derive(Clone)] diff --git a/src/hittable/model.rs b/src/hittable/model.rs index 1a652be..6357ab1 100644 --- a/src/hittable/model.rs +++ b/src/hittable/model.rs @@ -1,7 +1,12 @@ use std::sync::Arc; use std::vec::Vec; -use crate::{hittable::{HitRecord, Hittable, AABB, HittableList, Triangle}, material::Material, ray::Ray, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, HittableList, Triangle, AABB}, + material::Material, + ray::Ray, + vec3::Vec3, +}; pub struct Model { faces: HittableList, @@ -10,7 +15,15 @@ pub struct Model { impl Model { fn parse_face_triplet(triplet: &str) -> Option<(isize, Option<isize>, Option<isize>)> { let mut triplet_iter = triplet.split("/"); - Some((triplet_iter.next()?.parse::<isize>().ok()?, triplet_iter.next().and_then(|val| val.parse::<isize>().ok()) , triplet_iter.next().and_then(|val| val.parse::<isize>().ok()))) + Some(( + triplet_iter.next()?.parse::<isize>().ok()?, + triplet_iter + .next() + .and_then(|val| val.parse::<isize>().ok()), + triplet_iter + .next() + .and_then(|val| val.parse::<isize>().ok()), + )) } pub fn from_obj(obj_data: &str, material: Arc<dyn Material>) -> Self { let mut geometric_vertices: Vec<Vec3> = Vec::new(); @@ -34,95 +47,85 @@ impl Model { None => { eprintln!("Malformed {} entry in OBJ: Missing x!", operator); continue; - }, - Some(val) => { - match val.parse::<f64>() { - Err(_) => { - eprintln!("Malformed {} entry in OBJ: Malformed f64 x!", operator); - continue; - }, - Ok(val) => val, - } } + Some(val) => match val.parse::<f64>() { + Err(_) => { + eprintln!("Malformed {} entry in OBJ: Malformed f64 x!", operator); + continue; + } + Ok(val) => val, + }, }; let y = match entry_iter.next() { None => { eprintln!("Malformed {} entry in OBJ: Missing y!", operator); continue; - }, - Some(val) => { - match val.parse::<f64>() { - Err(_) => { - eprintln!("Malformed {} entry in OBJ: Malformed f64 y!", operator); - continue; - }, - Ok(val) => val, - } } + Some(val) => match val.parse::<f64>() { + Err(_) => { + eprintln!("Malformed {} entry in OBJ: Malformed f64 y!", operator); + continue; + } + Ok(val) => val, + }, }; let z = match entry_iter.next() { None => { eprintln!("Malformed {} entry in OBJ: Missing z!", operator); continue; - }, - Some(val) => { - match val.parse::<f64>() { - Err(_) => { - eprintln!("Malformed {} entry in OBJ: Malformed f64 z!", operator); - continue; - }, - Ok(val) => val, - } } + Some(val) => match val.parse::<f64>() { + Err(_) => { + eprintln!("Malformed {} entry in OBJ: Malformed f64 z!", operator); + continue; + } + Ok(val) => val, + }, }; // who cares about w match operator { - "v" => geometric_vertices.push(Vec3 {x, y, z}), - "vn" => vertex_normals.push(Vec3 {x, y, z}), + "v" => geometric_vertices.push(Vec3 { x, y, z }), + "vn" => vertex_normals.push(Vec3 { x, y, z }), _ => panic!(), } - }, + } "vt" => { let u = match entry_iter.next() { None => { eprintln!("Malformed vt entry in OBJ: Missing u!"); continue; - }, - Some(val) => { - match val.parse::<f64>() { - Err(_) => { - eprintln!("Malformed vt entry in OBJ: Malformed f64 u!"); - continue; - }, - Ok(val) => val, - } } + Some(val) => match val.parse::<f64>() { + Err(_) => { + eprintln!("Malformed vt entry in OBJ: Malformed f64 u!"); + continue; + } + Ok(val) => val, + }, }; let v = match entry_iter.next() { None => { eprintln!("Malformed vt entry in OBJ: Missing v!"); continue; - }, - Some(val) => { - match val.parse::<f64>() { - Err(_) => { - eprintln!("Malformed v entry in OBJ: Malformed f64 v!"); - continue; - }, - Ok(val) => val, - } } + Some(val) => match val.parse::<f64>() { + Err(_) => { + eprintln!("Malformed v entry in OBJ: Malformed f64 v!"); + continue; + } + Ok(val) => val, + }, }; // who cares about w texture_vertices.push((u, v)); - }, + } "f" => { - let mut triplets : Vec<(isize, Option<isize>, Option<isize>)> = Vec::new(); + let mut triplets: Vec<(isize, Option<isize>, Option<isize>)> = Vec::new(); for triplet in entry_iter { match Self::parse_face_triplet(triplet) { None => { eprintln!("Encountered malformed triplet in f operator!"); - }, + } Some(val) => { triplets.push(val); } @@ -163,7 +166,7 @@ impl Model { if let Some(vn2) = triplets.get(2).unwrap().2 { if vn0 != vn1 || vn1 != vn2 { eprintln!("Unsupported geometry in OBJ file: Multiple normals for face!"); - continue + continue; } let mut vn0 = vn0; if vn0 < 0 { @@ -171,16 +174,17 @@ impl Model { } else { vn0 = vn0 - 1; } - triangle.custom_normal = Some(vertex_normals.get(vn0 as usize).unwrap().unit_vector()); + triangle.custom_normal = + Some(vertex_normals.get(vn0 as usize).unwrap().unit_vector()); } } } faces.push(Arc::new(triangle)); - }, + } _ => { eprintln!("Ignoring unknown operator {} in OBJ!", operator); continue; - }, + } } } Self { diff --git a/src/hittable/sphere.rs b/src/hittable/sphere.rs index 783b788..f276366 100644 --- a/src/hittable/sphere.rs +++ b/src/hittable/sphere.rs @@ -1,9 +1,13 @@ -use std::sync::Arc; use std::f64::consts; +use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, vec3::Vec3}; use crate::ray::Ray; use crate::vec3::Point3; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::Material, + vec3::Vec3, +}; pub struct Sphere { pub center: Point3, @@ -54,8 +58,18 @@ impl Hittable for Sphere { fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> { Some(AABB { - minimum: &self.center - Vec3 { x: self.radius, y: self.radius, z: self.radius }, - maximum: &self.center + Vec3 { x: self.radius, y: self.radius, z: self.radius }, + minimum: &self.center + - Vec3 { + x: self.radius, + y: self.radius, + z: self.radius, + }, + maximum: &self.center + + Vec3 { + x: self.radius, + y: self.radius, + z: self.radius, + }, }) } } diff --git a/src/hittable/triangle.rs b/src/hittable/triangle.rs index 0fe5fc4..82b9e18 100644 --- a/src/hittable/triangle.rs +++ b/src/hittable/triangle.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::Material, + ray::Ray, + vec3::{Point3, Vec3}, +}; pub struct Triangle { pub v0: Point3, @@ -12,7 +17,9 @@ pub struct Triangle { impl Triangle { fn has_vertex_at_infinity(&self) -> bool { - self.v0.has_infinite_member() || self.v1.has_infinite_member() || self.v2.has_infinite_member() + self.v0.has_infinite_member() + || self.v1.has_infinite_member() + || self.v2.has_infinite_member() } } @@ -71,9 +78,9 @@ impl Hittable for Triangle { maximum: Point3 { x: self.v0.x.max(self.v1.x).max(self.v2.x) + 0.0001, y: self.v0.y.max(self.v1.y).max(self.v2.y) + 0.0001, - z: self.v0.z.max(self.v1.z).max(self.v2.z) + 0.0001, + z: self.v0.z.max(self.v1.z).max(self.v2.z) + 0.0001, }, - }) + }), } } } diff --git a/src/hittable/xy_rect.rs b/src/hittable/xy_rect.rs index 8421bae..2d7dbeb 100644 --- a/src/hittable/xy_rect.rs +++ b/src/hittable/xy_rect.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::Material, + ray::Ray, + vec3::{Point3, Vec3}, +}; pub struct XYRect { pub material: Arc<dyn Material>, @@ -13,7 +18,10 @@ pub struct XYRect { impl XYRect { fn has_infinite_bounds(&self) -> bool { - self.x0.is_infinite() || self.x1.is_infinite() || self.y0.is_infinite() || self.y1.is_infinite() + self.x0.is_infinite() + || self.x1.is_infinite() + || self.y0.is_infinite() + || self.y1.is_infinite() } } @@ -32,7 +40,11 @@ impl Hittable for XYRect { hit_record.u = (x - self.x0) / (self.x1 - self.x0); hit_record.v = (y - self.y0) / (self.y1 - self.y0); hit_record.t = t; - let outward_normal = Vec3 { x: 0.0, y: 0.0, z: 1.0 }; + let outward_normal = Vec3 { + x: 0.0, + y: 0.0, + z: 1.0, + }; hit_record.set_face_normal(ray, &outward_normal); hit_record.material = Some(self.material.clone()); hit_record.p = ray.at(t); @@ -42,7 +54,18 @@ impl Hittable for XYRect { fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> { match self.has_infinite_bounds() { true => None, - false => Some(AABB { minimum: Point3 { x: self.x0, y: self.y0, z: self.k - 0.0001 }, maximum: Point3 { x: self.x1, y: self.y1, z: self.k + 0.0001 } }), + false => Some(AABB { + minimum: Point3 { + x: self.x0, + y: self.y0, + z: self.k - 0.0001, + }, + maximum: Point3 { + x: self.x1, + y: self.y1, + z: self.k + 0.0001, + }, + }), } } } diff --git a/src/hittable/xz_rect.rs b/src/hittable/xz_rect.rs index 4761f36..c990de5 100644 --- a/src/hittable/xz_rect.rs +++ b/src/hittable/xz_rect.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::Material, + ray::Ray, + vec3::{Point3, Vec3}, +}; pub struct XZRect { pub material: Arc<dyn Material>, @@ -13,7 +18,10 @@ pub struct XZRect { impl XZRect { fn has_infinite_bounds(&self) -> bool { - self.x0.is_infinite() || self.x1.is_infinite() || self.z0.is_infinite() || self.z1.is_infinite() + self.x0.is_infinite() + || self.x1.is_infinite() + || self.z0.is_infinite() + || self.z1.is_infinite() } } @@ -32,7 +40,11 @@ impl Hittable for XZRect { hit_record.u = (x - self.x0) / (self.x1 - self.x0); hit_record.v = (z - self.z0) / (self.z1 - self.z0); hit_record.t = t; - let outward_normal = Vec3 { x: 0.0, y: 1.0, z: 0.0 }; + let outward_normal = Vec3 { + x: 0.0, + y: 1.0, + z: 0.0, + }; hit_record.set_face_normal(ray, &outward_normal); hit_record.material = Some(self.material.clone()); hit_record.p = ray.at(t); @@ -42,7 +54,18 @@ impl Hittable for XZRect { fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> { match self.has_infinite_bounds() { true => None, - false => Some(AABB { minimum: Point3 { x: self.x0, y: self.k - 0.0001, z: self.z0 }, maximum: Point3 { x: self.x1, y: self.k + 0.0001, z: self.z1 } }), + false => Some(AABB { + minimum: Point3 { + x: self.x0, + y: self.k - 0.0001, + z: self.z0, + }, + maximum: Point3 { + x: self.x1, + y: self.k + 0.0001, + z: self.z1, + }, + }), } } } diff --git a/src/hittable/yz_rect.rs b/src/hittable/yz_rect.rs index dd90bdb..db068dd 100644 --- a/src/hittable/yz_rect.rs +++ b/src/hittable/yz_rect.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}}; +use crate::{ + hittable::{HitRecord, Hittable, AABB}, + material::Material, + ray::Ray, + vec3::{Point3, Vec3}, +}; pub struct YZRect { pub material: Arc<dyn Material>, @@ -13,7 +18,10 @@ pub struct YZRect { impl YZRect { fn has_infinite_bounds(&self) -> bool { - self.y0.is_infinite() || self.y1.is_infinite() || self.z0.is_infinite() || self.z1.is_infinite() + self.y0.is_infinite() + || self.y1.is_infinite() + || self.z0.is_infinite() + || self.z1.is_infinite() } } @@ -32,7 +40,11 @@ impl Hittable for YZRect { hit_record.u = (y - self.y0) / (self.y1 - self.y0); hit_record.v = (z - self.z0) / (self.z1 - self.z0); hit_record.t = t; - let outward_normal = Vec3 { x: 1.0, y: 0.0, z: 0.0 }; + let outward_normal = Vec3 { + x: 1.0, + y: 0.0, + z: 0.0, + }; hit_record.set_face_normal(ray, &outward_normal); hit_record.material = Some(self.material.clone()); hit_record.p = ray.at(t); @@ -42,7 +54,18 @@ impl Hittable for YZRect { fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> { match self.has_infinite_bounds() { true => None, - false => Some(AABB { minimum: Point3 { x: self.k - 0.0001, y: self.y0, z: self.z0 }, maximum: Point3 { x: self.k + 0.0001, y: self.y1, z: self.z1 } }), + false => Some(AABB { + minimum: Point3 { + x: self.k - 0.0001, + y: self.y0, + z: self.z0, + }, + maximum: Point3 { + x: self.k + 0.0001, + y: self.y1, + z: self.z1, + }, + }), } } } diff --git a/src/main.rs b/src/main.rs index 0fe2df9..1e889e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,24 @@ mod camera; +mod display; mod hittable; mod material; mod ray; +mod scenes; +mod texture; mod util; mod vec3; -mod display; -mod texture; -mod scenes; -use std::{sync::{Arc, mpsc}, thread}; +use std::{ + sync::{mpsc, Arc}, + thread, +}; use camera::Camera; -use hittable::Hittable; use display::{Display, Image, Pixelflut}; +use hittable::Hittable; use ray::Ray; -use vec3::{Vec3, Color, Point3}; use scenes::get_scene; +use vec3::{Color, Vec3}; struct PixelUpdate { color: Color, @@ -33,7 +36,7 @@ fn ray_color(ray: &Ray, background: &Color, world: &dyn Hittable, depth: u32) -> } match world.hit(ray, 0.001, f64::INFINITY) { None => background.clone(), - Some(mut rec) => { + Some(rec) => { let mut scattered = Ray::new(); let mut attenuation = Color::new(); if let Some(material) = &rec.material { @@ -44,13 +47,26 @@ fn ray_color(ray: &Ray, background: &Color, world: &dyn Hittable, depth: u32) -> emitted + attenuation * ray_color(&scattered, background, world, depth - 1) } } else { - Color { x: 0.0, y: 0.0, z: 0.0 } + Color { + x: 0.0, + y: 0.0, + z: 0.0, + } } - }, + } } } -fn render(image_width: u32, image_height: u32, samples_per_pixel: u32, max_depth: u32, world: Arc<dyn Hittable>, background: Color, camera: Arc<Camera>, tx: mpsc::Sender<PixelUpdate>) { +fn render( + image_width: u32, + image_height: u32, + samples_per_pixel: u32, + max_depth: u32, + world: Arc<dyn Hittable>, + background: Color, + camera: Arc<Camera>, + tx: mpsc::Sender<PixelUpdate>, +) { for j in (0..image_height).rev() { for i in 0..image_width { for _ in 0..samples_per_pixel { @@ -58,7 +74,12 @@ fn render(image_width: u32, image_height: u32, samples_per_pixel: u32, max_depth let v = ((j as f64) + rand::random::<f64>()) / ((image_height - 1) as f64); let ray = camera.get_ray(u, v); - tx.send(PixelUpdate { color: ray_color(&ray, &background, world.as_ref(), max_depth), x: i as usize, y: j as usize}).unwrap(); + tx.send(PixelUpdate { + color: ray_color(&ray, &background, world.as_ref(), max_depth), + x: i as usize, + y: j as usize, + }) + .unwrap(); } } } @@ -76,27 +97,67 @@ fn main() { const TIME_START: f64 = 0.0; const TIME_END: f64 = 1.0; // World - let (world, lookfrom, lookat, vfov, aperture, background) = get_scene(std::env::args().nth(1).unwrap_or("0".to_string()).trim().parse().unwrap_or(0)); + let (world, lookfrom, lookat, vfov, aperture, background) = get_scene( + std::env::args() + .nth(1) + .unwrap_or("0".to_string()) + .trim() + .parse() + .unwrap_or(0), + ); // Camera - let vup = Vec3 { x: 0.0, y: 1.0, z: 0.0 }; + let vup = Vec3 { + x: 0.0, + y: 1.0, + z: 0.0, + }; let dist_to_focus = 10.0; - let cam = Arc::new(Camera::new(lookfrom, lookat, vup, vfov, ASPECT_RATIO, aperture, dist_to_focus, TIME_START, TIME_END)); + let cam = Arc::new(Camera::new( + lookfrom, + lookat, + vup, + vfov, + ASPECT_RATIO, + aperture, + dist_to_focus, + TIME_START, + TIME_END, + )); // Render // let mut final_image = Image::new(IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize); - let mut final_image = Pixelflut::new("192.168.0.38:1337", 0, 0, IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize); + let mut final_image = Pixelflut::new( + "192.168.0.38:1337", + 0, + 0, + IMAGE_WIDTH as usize, + IMAGE_HEIGHT as usize, + ); let (tx, rx) = mpsc::channel::<PixelUpdate>(); for _ in 0..THREAD_COUNT { let sender = tx.clone(); let world_ref = world.clone(); let camera_ref = cam.clone(); let background_clone = background.clone(); - thread::spawn( || { - render(IMAGE_WIDTH, IMAGE_HEIGHT, SAMPLES_PER_PIXEL / THREAD_COUNT, MAX_DEPTH, world_ref, background_clone, camera_ref, sender); + thread::spawn(|| { + render( + IMAGE_WIDTH, + IMAGE_HEIGHT, + SAMPLES_PER_PIXEL / THREAD_COUNT, + MAX_DEPTH, + world_ref, + background_clone, + camera_ref, + sender, + ); }); } - let expected_updates: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_HEIGHT as u64 * IMAGE_WIDTH as u64; - let print_frequency: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_WIDTH as u64; + let expected_updates: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 + * THREAD_COUNT as u64 + * IMAGE_HEIGHT as u64 + * IMAGE_WIDTH as u64; + let print_frequency: u64 = + (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_WIDTH as u64; let print_frequency = print_frequency * 3; let mut update_count: u64 = 0; loop { @@ -105,11 +166,14 @@ fn main() { final_image.add_sample(update.x, update.y, update.color); if update_count % print_frequency == 0 { final_image.maybe_update(); - eprint!("\rCurrent completion: {:.2}%", (update_count as f64 / expected_updates as f64) * 100.0) + eprint!( + "\rCurrent completion: {:.2}%", + (update_count as f64 / expected_updates as f64) * 100.0 + ) } } else { if Arc::strong_count(&world) == 1 { - break + break; } } } diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs index 1a49f73..af6f9b0 100644 --- a/src/material/dielectric.rs +++ b/src/material/dielectric.rs @@ -1,9 +1,9 @@ use std::ops::Neg; use super::Material; -use crate::{hittable::HitRecord, vec3::Vec3}; -use crate::vec3::Color; use crate::ray::Ray; +use crate::vec3::Color; +use crate::{hittable::HitRecord, vec3::Vec3}; pub struct DielectricAttenuation { pub albedo: Color, @@ -25,7 +25,13 @@ impl Dielectric { } impl Material for Dielectric { - fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + ray_in: &Ray, + hit_record: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { if let Some(props) = &self.attenuation { let outward_normal = if hit_record.front_face { hit_record.normal.clone() @@ -40,9 +46,17 @@ impl Material for Dielectric { *attenuation = props.albedo.clone(); } } else { - *attenuation = Color { x: 1.0, y: 1.0, z: 1.0 }; + *attenuation = Color { + x: 1.0, + y: 1.0, + z: 1.0, + }; } - let refraction_ratio = if hit_record.front_face { 1.0 / self.index_of_refraction } else { self.index_of_refraction }; + let refraction_ratio = if hit_record.front_face { + 1.0 / self.index_of_refraction + } else { + self.index_of_refraction + }; let unit_direction = ray_in.direction.unit_vector(); let cos_theta = hit_record.normal.dot(&-&unit_direction).min(1.0); let sin_theta = (1.0 - cos_theta * cos_theta).sqrt(); @@ -50,13 +64,18 @@ impl Material for Dielectric { let cannot_refract = refraction_ratio * sin_theta > 1.0; let direction: Vec3; - if cannot_refract || Self::reflectance(cos_theta, refraction_ratio) > rand::random::<f64>() { + if cannot_refract || Self::reflectance(cos_theta, refraction_ratio) > rand::random::<f64>() + { direction = unit_direction.reflect(&hit_record.normal) } else { direction = unit_direction.refract(&hit_record.normal, refraction_ratio) } - *scattered = Ray { origin: hit_record.p.clone(), direction, time: ray_in.time }; + *scattered = Ray { + origin: hit_record.p.clone(), + direction, + time: ray_in.time, + }; true } } diff --git a/src/material/diffuse_light.rs b/src/material/diffuse_light.rs index fecbcff..4feca3b 100644 --- a/src/material/diffuse_light.rs +++ b/src/material/diffuse_light.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use super::Material; -use crate::{hittable::HitRecord, texture::Texture, vec3::Point3}; -use crate::vec3::Color; -use crate::texture::SolidColor; use crate::ray::Ray; +use crate::texture::SolidColor; +use crate::vec3::Color; +use crate::{hittable::HitRecord, texture::Texture, vec3::Point3}; pub struct DiffuseLight { emit: Arc<dyn Texture>, diff --git a/src/material/isotropic.rs b/src/material/isotropic.rs index f59fa7d..9949abd 100644 --- a/src/material/isotropic.rs +++ b/src/material/isotropic.rs @@ -1,32 +1,39 @@ use std::sync::Arc; use super::Material; -use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3}; -use crate::vec3::Color; -use crate::texture::SolidColor; use crate::ray::Ray; +use crate::vec3::Color; +use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3}; pub struct Isotropic { albedo: Arc<dyn Texture>, } impl Isotropic { - pub fn from_color(color: Color) -> Self { - Self { - albedo: Arc::new(SolidColor::from_color(color)), - } - } + // pub fn from_color(color: Color) -> Self { + // Self { + // albedo: Arc::new(SolidColor::from_color(color)), + // } + // } pub fn from_texture(texture: Arc<dyn Texture>) -> Self { - Self { - albedo: texture, - } + Self { albedo: texture } } } impl Material for Isotropic { - fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { - *scattered = Ray { origin: hit_record.p.clone(), direction: Vec3::random_in_unit_sphere(), time: ray_in.time }; + fn scatter( + &self, + ray_in: &Ray, + hit_record: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { + *scattered = Ray { + origin: hit_record.p.clone(), + direction: Vec3::random_in_unit_sphere(), + time: ray_in.time, + }; *attenuation = self.albedo.value(hit_record.u, hit_record.v, &hit_record.p); true } diff --git a/src/material/lambertian.rs b/src/material/lambertian.rs index 95f698e..fed26f9 100644 --- a/src/material/lambertian.rs +++ b/src/material/lambertian.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use super::Material; -use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3}; -use crate::vec3::Color; -use crate::texture::SolidColor; use crate::ray::Ray; +use crate::texture::SolidColor; +use crate::vec3::Color; +use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3}; pub struct Lambertian { pub albedo: Arc<dyn Texture>, @@ -13,13 +13,21 @@ pub struct Lambertian { impl Lambertian { pub fn from_color(color: Color) -> Self { Self { - albedo: Arc::new(SolidColor { color_value: color.clone() }), + albedo: Arc::new(SolidColor { + color_value: color.clone(), + }), } } } impl Material for Lambertian { - fn scatter(&self, ray_in : &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + ray_in: &Ray, + hit_record: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { let mut scatter_direction = &hit_record.normal + Vec3::random_unit_vector(); // Catch zero-vector scatter directions that will generate issues later @@ -27,7 +35,11 @@ impl Material for Lambertian { scatter_direction = hit_record.normal.clone(); } - *scattered = Ray { origin: hit_record.p.clone(), direction: scatter_direction, time: ray_in.time }; + *scattered = Ray { + origin: hit_record.p.clone(), + direction: scatter_direction, + time: ray_in.time, + }; *attenuation = self.albedo.value(hit_record.u, hit_record.v, &hit_record.p); true } diff --git a/src/material/metal.rs b/src/material/metal.rs index 2865a2f..638e5e4 100644 --- a/src/material/metal.rs +++ b/src/material/metal.rs @@ -1,7 +1,7 @@ use super::Material; -use crate::{hittable::HitRecord, vec3::Vec3}; -use crate::vec3::Color; use crate::ray::Ray; +use crate::vec3::Color; +use crate::{hittable::HitRecord, vec3::Vec3}; pub struct Metal { pub albedo: Color, @@ -9,9 +9,19 @@ pub struct Metal { } impl Material for Metal { - fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + ray_in: &Ray, + hit_record: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { let reflected = ray_in.direction.unit_vector().reflect(&hit_record.normal); - *scattered = Ray { origin: hit_record.p.clone(), direction: reflected + self.fuzz * Vec3::random_in_unit_sphere(), time: ray_in.time }; + *scattered = Ray { + origin: hit_record.p.clone(), + direction: reflected + self.fuzz * Vec3::random_in_unit_sphere(), + time: ray_in.time, + }; *attenuation = self.albedo.clone(); scattered.direction.dot(&hit_record.normal) > 0.0 } diff --git a/src/material/mod.rs b/src/material/mod.rs index c292ea1..cded09b 100644 --- a/src/material/mod.rs +++ b/src/material/mod.rs @@ -10,13 +10,23 @@ pub use diffuse_light::DiffuseLight; mod isotropic; pub use isotropic::Isotropic; -use crate::{hittable::HitRecord, vec3::Point3}; -use crate::vec3::Color; use crate::ray::Ray; +use crate::vec3::Color; +use crate::{hittable::HitRecord, vec3::Point3}; pub trait Material: Send + Sync { fn emitted(&self, _: f64, _: f64, _: &Point3) -> Color { - Color { x: 0.0, y: 0.0, z: 0.0 } + Color { + x: 0.0, + y: 0.0, + z: 0.0, + } } - fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool; + fn scatter( + &self, + ray_in: &Ray, + hit_record: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool; } @@ -9,9 +9,17 @@ pub struct Ray { impl Ray { pub fn new() -> Ray { Ray { - origin: Point3 { x: 0.0, y: 0.0, z: 0.0 }, - direction: Vec3 { x: 0.0, y:0.0, z: 0.0}, - time: 0.0 + origin: Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + direction: Vec3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + time: 0.0, } } diff --git a/src/scenes.rs b/src/scenes.rs index 54f6eb3..096055e 100644 --- a/src/scenes.rs +++ b/src/scenes.rs @@ -1,23 +1,25 @@ use std::sync::Arc; -use crate::hittable::{ConstantMedium, Hittable}; -use crate::hittable::HittableBox; -use crate::hittable::HittableList; -use crate::material::{Dielectric, DielectricAttenuation, DiffuseLight, Lambertian, Material, Metal}; -use crate::hittable::instance::RotateY; +use crate::hittable::instance::Moving; use crate::hittable::instance::RotateX; +use crate::hittable::instance::RotateY; use crate::hittable::instance::RotateZ; -use crate::hittable::Sphere; use crate::hittable::instance::Translate; -use crate::vec3::{Point3, Vec3, Color}; use crate::hittable::BVHNode; -use crate::texture::{CheckerTexture, ImageTexture, NoiseTexture, SolidColor}; +use crate::hittable::HittableBox; +use crate::hittable::HittableList; +use crate::hittable::Model; +use crate::hittable::Sphere; +use crate::hittable::Triangle; use crate::hittable::XYRect; use crate::hittable::XZRect; use crate::hittable::YZRect; -use crate::hittable::Triangle; -use crate::hittable::Model; -use crate::hittable::instance::Moving; +use crate::hittable::{ConstantMedium, Hittable}; +use crate::material::{ + Dielectric, DielectricAttenuation, DiffuseLight, Lambertian, Material, Metal, +}; +use crate::texture::{CheckerTexture, ImageTexture, NoiseTexture, SolidColor}; +use crate::vec3::{Color, Point3, Vec3}; pub fn get_scene(id: u32) -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { match id { @@ -37,141 +39,647 @@ pub fn get_scene(id: u32) -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color fn random_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut world = HittableList::new(); - let checker = Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 })); + let checker = Arc::new(CheckerTexture::from_colors( + Color { + x: 0.2, + y: 0.3, + z: 0.1, + }, + Color { + x: 0.9, + y: 0.9, + z: 0.9, + }, + )); let ground_material = Arc::new(Lambertian { albedo: checker }); - world.add(Arc::new(Sphere{ center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: ground_material })); + world.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: -1000.0, + z: 0.0, + }, + radius: 1000.0, + material: ground_material, + })); for a in -11..11 { for b in -11..11 { let choose_mat = rand::random::<f64>(); - let center = Point3 { x: (a as f64) + 0.9 * rand::random::<f64>(), y: 0.2, z: (b as f64) + 0.9 * rand::random::<f64>() }; - - if (¢er - Point3 { x: 4.0, y: 0.3, z: 0.0 }).length() > 0.9 { + let center = Point3 { + x: (a as f64) + 0.9 * rand::random::<f64>(), + y: 0.2, + z: (b as f64) + 0.9 * rand::random::<f64>(), + }; + + if (¢er + - Point3 { + x: 4.0, + y: 0.3, + z: 0.0, + }) + .length() + > 0.9 + { let sphere_material: Arc<dyn Material>; if choose_mat < 0.8 { - let albedo = Arc::new(SolidColor::from_color(Color::random() * Color::random())); + let albedo = + Arc::new(SolidColor::from_color(Color::random() * Color::random())); sphere_material = Arc::new(Lambertian { albedo }); - world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material })); + world.add(Arc::new(Sphere { + center, + radius: 0.2, + material: sphere_material, + })); } else if choose_mat < 0.95 { let albedo = Color::random_in_range(0.5, 1.0); let fuzz = rand::random::<f64>() / 2.0; sphere_material = Arc::new(Metal { albedo, fuzz }); - world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material })); + world.add(Arc::new(Sphere { + center, + radius: 0.2, + material: sphere_material, + })); } else { - sphere_material = Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }); - world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material })); + sphere_material = Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: Some(DielectricAttenuation { + albedo: Color { + x: 0.5, + y: 0.5, + z: 0.8, + }, + constant: 0.8, + }), + }); + world.add(Arc::new(Sphere { + center, + radius: 0.2, + material: sphere_material, + })); } } } } - let material1 = Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }); - world.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material1 })); - - let material2 = Arc::new(Lambertian { albedo: Arc::new(SolidColor::from_color(Color { x: 0.4, y: 0.2, z: 0.1 })) }); - world.add(Arc::new(Sphere { center: Point3 { x: -4.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material2 })); - - let material3 = Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.0 }); - world.add(Arc::new(Sphere { center: Point3 { x: 4.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material3 })); - - (Arc::new(BVHNode::new(&world, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.1, Color { x: 0.7, y: 0.8, z: 1.0 }) + let material1 = Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: Some(DielectricAttenuation { + albedo: Color { + x: 0.5, + y: 0.5, + z: 0.8, + }, + constant: 0.8, + }), + }); + world.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 1.0, + z: 0.0, + }, + radius: 1.0, + material: material1, + })); + + let material2 = Arc::new(Lambertian { + albedo: Arc::new(SolidColor::from_color(Color { + x: 0.4, + y: 0.2, + z: 0.1, + })), + }); + world.add(Arc::new(Sphere { + center: Point3 { + x: -4.0, + y: 1.0, + z: 0.0, + }, + radius: 1.0, + material: material2, + })); + + let material3 = Arc::new(Metal { + albedo: Color { + x: 0.7, + y: 0.6, + z: 0.5, + }, + fuzz: 0.0, + }); + world.add(Arc::new(Sphere { + center: Point3 { + x: 4.0, + y: 1.0, + z: 0.0, + }, + radius: 1.0, + material: material3, + })); + + ( + Arc::new(BVHNode::new(&world, 0.0, 1.0)), + Point3 { + x: 13.0, + y: 2.0, + z: 3.0, + }, + Point3::new(), + 20.0, + 0.1, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } fn two_spheres() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let checker = Arc::new(Lambertian { albedo: Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 })) }); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -10.0, z: 0.0 }, radius: 10.0, material: checker.clone() })); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 10.0, z: 0.0 }, radius: 10.0, material: checker })); - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) + let checker = Arc::new(Lambertian { + albedo: Arc::new(CheckerTexture::from_colors( + Color { + x: 0.2, + y: 0.3, + z: 0.1, + }, + Color { + x: 0.9, + y: 0.9, + z: 0.9, + }, + )), + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: -10.0, + z: 0.0, + }, + radius: 10.0, + material: checker.clone(), + })); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 10.0, + z: 0.0, + }, + radius: 10.0, + material: checker, + })); + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 13.0, + y: 2.0, + z: 3.0, + }, + Point3::new(), + 20.0, + 0.0, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } fn two_perlin_spheres() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) }); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: pertext.clone() })); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 2.0, z: 0.0 }, radius: 2.0, material: pertext.clone() })); - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) + let pertext = Arc::new(Lambertian { + albedo: Arc::new(NoiseTexture::new(4.0)), + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: -1000.0, + z: 0.0, + }, + radius: 1000.0, + material: pertext.clone(), + })); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 2.0, + z: 0.0, + }, + radius: 2.0, + material: pertext.clone(), + })); + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 13.0, + y: 2.0, + z: 3.0, + }, + Point3::new(), + 20.0, + 0.0, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } fn earth() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let earth_texture = Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec())); - let earth_surface = Arc::new(Lambertian { albedo: earth_texture }); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 0.0, z: 0.0 }, radius: 2.0, material: earth_surface })); - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) + let earth_texture = Arc::new(ImageTexture::from_bmp_data( + &include_bytes!("../res/earthmap.bmp").to_vec(), + )); + let earth_surface = Arc::new(Lambertian { + albedo: earth_texture, + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + radius: 2.0, + material: earth_surface, + })); + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 13.0, + y: 2.0, + z: 3.0, + }, + Point3::new(), + 20.0, + 0.0, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } fn simple_light() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) }); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: pertext.clone() })); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 2.0, z: 0.0 }, radius: 2.0, material: pertext.clone() })); - let diff_light = Arc::new(DiffuseLight::from_color(Color { x: 4.0, y: 4.0, z: 4.0 })); - objects.add(Arc::new(XYRect { material: diff_light, x0: 3.0, x1: 5.0, y0: 1.0, y1: 3.0, k: -2.0 })); - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 26.0, y: 3.0, z: 6.0}, Point3 { x: 0.0, y: 2.0, z: 0.0}, 20.0, 0.0, Color::new()) + let pertext = Arc::new(Lambertian { + albedo: Arc::new(NoiseTexture::new(4.0)), + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: -1000.0, + z: 0.0, + }, + radius: 1000.0, + material: pertext.clone(), + })); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 2.0, + z: 0.0, + }, + radius: 2.0, + material: pertext.clone(), + })); + let diff_light = Arc::new(DiffuseLight::from_color(Color { + x: 4.0, + y: 4.0, + z: 4.0, + })); + objects.add(Arc::new(XYRect { + material: diff_light, + x0: 3.0, + x1: 5.0, + y0: 1.0, + y1: 3.0, + k: -2.0, + })); + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 26.0, + y: 3.0, + z: 6.0, + }, + Point3 { + x: 0.0, + y: 2.0, + z: 0.0, + }, + 20.0, + 0.0, + Color::new(), + ) } fn cornell_box() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let red = Arc::new(Lambertian::from_color(Color { x: 0.65, y: 0.05, z: 0.05 })); - let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 })); - let green = Arc::new(Lambertian::from_color(Color { x: 0.12, y: 0.45, z: 0.15 })); - let light = Arc::new(DiffuseLight::from_color(Color { x: 15.0, y: 15.0, z: 15.0 })); - - objects.add(Arc::new(YZRect { material: green, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 })); - objects.add(Arc::new(YZRect { material: red, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 })); - objects.add(Arc::new(XZRect { material: light, x0: 213.0, x1: 343.0, z0: 227.0, z1: 332.0, k: 554.0 })); - objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 })); - objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 })); - objects.add(Arc::new(XYRect { material: white.clone(), x0: 0.0, x1: 555.0, y0: 0.0, y1: 555.0, k: 555.0 })); + let red = Arc::new(Lambertian::from_color(Color { + x: 0.65, + y: 0.05, + z: 0.05, + })); + let white = Arc::new(Lambertian::from_color(Color { + x: 0.73, + y: 0.73, + z: 0.73, + })); + let green = Arc::new(Lambertian::from_color(Color { + x: 0.12, + y: 0.45, + z: 0.15, + })); + let light = Arc::new(DiffuseLight::from_color(Color { + x: 15.0, + y: 15.0, + z: 15.0, + })); + + objects.add(Arc::new(YZRect { + material: green, + y0: 0.0, + y1: 555.0, + z0: 0.0, + z1: 555.0, + k: 555.0, + })); + objects.add(Arc::new(YZRect { + material: red, + y0: 0.0, + y1: 555.0, + z0: 0.0, + z1: 555.0, + k: 0.0, + })); + objects.add(Arc::new(XZRect { + material: light, + x0: 213.0, + x1: 343.0, + z0: 227.0, + z1: 332.0, + k: 554.0, + })); + objects.add(Arc::new(XZRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + z0: 0.0, + z1: 555.0, + k: 0.0, + })); + objects.add(Arc::new(XZRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + z0: 0.0, + z1: 555.0, + k: 555.0, + })); + objects.add(Arc::new(XYRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + y0: 0.0, + y1: 555.0, + k: 555.0, + })); //objects.add(Arc::new(HittableBox::new(Point3 { x: 130.0, y: 0.0, z: 65.0 }, Point3 { x: 295.0, y: 165.0, z: 230.0 }, white.clone()))); //objects.add(Arc::new(HittableBox::new(Point3 { x: 265.0, y: 0.0, z: 295.0 }, Point3 { x: 430.0, y: 330.0, z: 460.0 }, white.clone()))); - let box_1 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 330.0, z: 165.0 }, white.clone())); + let box_1 = Arc::new(HittableBox::new( + Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + Point3 { + x: 165.0, + y: 330.0, + z: 165.0, + }, + white.clone(), + )); let box_1 = Arc::new(RotateY::new(box_1, 15.0)); - let box_1 = Arc::new(Translate { hittable: box_1, offset: Point3 { x: 265.0, y: 0.0, z: 295.0 } }); + let box_1 = Arc::new(Translate { + hittable: box_1, + offset: Point3 { + x: 265.0, + y: 0.0, + z: 295.0, + }, + }); objects.add(box_1); - let box_2 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 165.0, z: 165.0 }, white.clone())); + let box_2 = Arc::new(HittableBox::new( + Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + Point3 { + x: 165.0, + y: 165.0, + z: 165.0, + }, + white.clone(), + )); let box_2 = Arc::new(RotateY::new(box_2, -18.0)); - let box_2 = Arc::new(Translate { hittable: box_2, offset: Point3 { x: 130.0, y: 0.0, z: 65.0 } }); + let box_2 = Arc::new(Translate { + hittable: box_2, + offset: Point3 { + x: 130.0, + y: 0.0, + z: 65.0, + }, + }); objects.add(box_2); - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 278.0, y: 278.0, z: -800.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new()) + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 278.0, + y: 278.0, + z: -800.0, + }, + Point3 { + x: 278.0, + y: 278.0, + z: 0.0, + }, + 40.0, + 0.0, + Color::new(), + ) } fn cornell_smoke() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let red = Arc::new(Lambertian::from_color(Color { x: 0.65, y: 0.05, z: 0.05 })); - let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 })); - let green = Arc::new(Lambertian::from_color(Color { x: 0.12, y: 0.45, z: 0.15 })); - let light = Arc::new(DiffuseLight::from_color(Color { x: 7.0, y: 7.0, z: 7.0 })); - - objects.add(Arc::new(YZRect { material: green, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 })); - objects.add(Arc::new(YZRect { material: red, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 })); - objects.add(Arc::new(XZRect { material: light, x0: 113.0, x1: 443.0, z0: 127.0, z1: 432.0, k: 554.0 })); - objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 })); - objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 })); - objects.add(Arc::new(XYRect { material: white.clone(), x0: 0.0, x1: 555.0, y0: 0.0, y1: 555.0, k: 555.0 })); + let red = Arc::new(Lambertian::from_color(Color { + x: 0.65, + y: 0.05, + z: 0.05, + })); + let white = Arc::new(Lambertian::from_color(Color { + x: 0.73, + y: 0.73, + z: 0.73, + })); + let green = Arc::new(Lambertian::from_color(Color { + x: 0.12, + y: 0.45, + z: 0.15, + })); + let light = Arc::new(DiffuseLight::from_color(Color { + x: 7.0, + y: 7.0, + z: 7.0, + })); + + objects.add(Arc::new(YZRect { + material: green, + y0: 0.0, + y1: 555.0, + z0: 0.0, + z1: 555.0, + k: 555.0, + })); + objects.add(Arc::new(YZRect { + material: red, + y0: 0.0, + y1: 555.0, + z0: 0.0, + z1: 555.0, + k: 0.0, + })); + objects.add(Arc::new(XZRect { + material: light, + x0: 113.0, + x1: 443.0, + z0: 127.0, + z1: 432.0, + k: 554.0, + })); + objects.add(Arc::new(XZRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + z0: 0.0, + z1: 555.0, + k: 0.0, + })); + objects.add(Arc::new(XZRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + z0: 0.0, + z1: 555.0, + k: 555.0, + })); + objects.add(Arc::new(XYRect { + material: white.clone(), + x0: 0.0, + x1: 555.0, + y0: 0.0, + y1: 555.0, + k: 555.0, + })); //objects.add(Arc::new(HittableBox::new(Point3 { x: 130.0, y: 0.0, z: 65.0 }, Point3 { x: 295.0, y: 165.0, z: 230.0 }, white.clone()))); //objects.add(Arc::new(HittableBox::new(Point3 { x: 265.0, y: 0.0, z: 295.0 }, Point3 { x: 430.0, y: 330.0, z: 460.0 }, white.clone()))); - let box_1 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 330.0, z: 165.0 }, white.clone())); + let box_1 = Arc::new(HittableBox::new( + Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + Point3 { + x: 165.0, + y: 330.0, + z: 165.0, + }, + white.clone(), + )); let box_1 = Arc::new(RotateY::new(box_1, 15.0)); - let box_1 = Arc::new(Translate { hittable: box_1, offset: Point3 { x: 265.0, y: 0.0, z: 295.0 } }); - let box_2 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 165.0, z: 165.0 }, white.clone())); + let box_1 = Arc::new(Translate { + hittable: box_1, + offset: Point3 { + x: 265.0, + y: 0.0, + z: 295.0, + }, + }); + let box_2 = Arc::new(HittableBox::new( + Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + Point3 { + x: 165.0, + y: 165.0, + z: 165.0, + }, + white.clone(), + )); let box_2 = Arc::new(RotateY::new(box_2, -18.0)); - let box_2 = Arc::new(Translate { hittable: box_2, offset: Point3 { x: 130.0, y: 0.0, z: 65.0 } }); - - objects.add(Arc::new(ConstantMedium::new(box_1, 0.01, Arc::new(SolidColor::from_color(Color { x: 0.0, y: 0.0, z: 0.0 }))))); - objects.add(Arc::new(ConstantMedium::new(box_2, 0.01, Arc::new(SolidColor::from_color(Color { x: 1.0, y: 1.0, z: 1.0 }))))); - - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 278.0, y: 278.0, z: -800.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new()) + let box_2 = Arc::new(Translate { + hittable: box_2, + offset: Point3 { + x: 130.0, + y: 0.0, + z: 65.0, + }, + }); + + objects.add(Arc::new(ConstantMedium::new( + box_1, + 0.01, + Arc::new(SolidColor::from_color(Color { + x: 0.0, + y: 0.0, + z: 0.0, + })), + ))); + objects.add(Arc::new(ConstantMedium::new( + box_2, + 0.01, + Arc::new(SolidColor::from_color(Color { + x: 1.0, + y: 1.0, + z: 1.0, + })), + ))); + + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 278.0, + y: 278.0, + z: -800.0, + }, + Point3 { + x: 278.0, + y: 278.0, + z: 0.0, + }, + 40.0, + 0.0, + Color::new(), + ) } fn final_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut boxes_1 = HittableList::new(); - let ground = Arc::new(Lambertian::from_color(Color { x: 0.48, y: 0.83, z: 0.53 })); + let ground = Arc::new(Lambertian::from_color(Color { + x: 0.48, + y: 0.83, + z: 0.53, + })); const BOXES_PER_SIDE: usize = 20; for i in 0..BOXES_PER_SIDE { @@ -183,70 +691,310 @@ fn final_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let x1 = x0 + w; let y1 = 1.0 + 100.0 * rand::random::<f64>(); let z1 = z0 + w; - boxes_1.add(Arc::new(HittableBox::new(Point3 { x: x0, y: y0, z: z0 }, Point3 { x: x1, y: y1, z: z1 }, ground.clone()))); + boxes_1.add(Arc::new(HittableBox::new( + Point3 { + x: x0, + y: y0, + z: z0, + }, + Point3 { + x: x1, + y: y1, + z: z1, + }, + ground.clone(), + ))); } } let mut objects = HittableList::new(); objects.add(Arc::new(BVHNode::new(&boxes_1, 0.0, 1.0))); - let light = Arc::new(DiffuseLight::from_color(Color { x: 7.0, y: 7.0, z: 7.0 })); - objects.add(Arc::new(XZRect { material: light.clone(), x0: 123.0, x1: 423.0, z0: 147.0, z1: 412.0, k: 554.0 })); - - let center_1 = Point3 { x: 400.0, y: 400.0, z: 200.0 }; - let center_2 = ¢er_1 + Vec3 { x: 30.0, y: 0.0, z: 0.0 }; - - let moving_sphere_material = Arc::new(Lambertian::from_color(Color { x: 0.7, y: 0.3, z: 0.1 })); - objects.add(Arc::new(Moving { hittable: Arc::new(Sphere { center: Point3::new(), radius: 50.0, material: moving_sphere_material }), offset_start: center_1, offset_end: center_2, time_start: 0.0, time_end: 1.0, })); - - objects.add(Arc::new(Sphere { center: Point3 { x: 260.0, y: 150.0, z: 45.0 }, radius: 50.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) })); - objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 150.0, z: 145.0 }, radius: 50.0, material: Arc::new(Metal { albedo: Color { x: 0.8, y: 0.8, z: 0.9 }, fuzz: 1.0 }) })); - - let boundary = Arc::new(Sphere { center: Point3 { x: 360.0, y: 150.0, z: 145.0 }, radius: 70.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) }); + let light = Arc::new(DiffuseLight::from_color(Color { + x: 7.0, + y: 7.0, + z: 7.0, + })); + objects.add(Arc::new(XZRect { + material: light.clone(), + x0: 123.0, + x1: 423.0, + z0: 147.0, + z1: 412.0, + k: 554.0, + })); + + let center_1 = Point3 { + x: 400.0, + y: 400.0, + z: 200.0, + }; + let center_2 = ¢er_1 + + Vec3 { + x: 30.0, + y: 0.0, + z: 0.0, + }; + + let moving_sphere_material = Arc::new(Lambertian::from_color(Color { + x: 0.7, + y: 0.3, + z: 0.1, + })); + objects.add(Arc::new(Moving { + hittable: Arc::new(Sphere { + center: Point3::new(), + radius: 50.0, + material: moving_sphere_material, + }), + offset_start: center_1, + offset_end: center_2, + time_start: 0.0, + time_end: 1.0, + })); + + objects.add(Arc::new(Sphere { + center: Point3 { + x: 260.0, + y: 150.0, + z: 45.0, + }, + radius: 50.0, + material: Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: None, + }), + })); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 150.0, + z: 145.0, + }, + radius: 50.0, + material: Arc::new(Metal { + albedo: Color { + x: 0.8, + y: 0.8, + z: 0.9, + }, + fuzz: 1.0, + }), + })); + + let boundary = Arc::new(Sphere { + center: Point3 { + x: 360.0, + y: 150.0, + z: 145.0, + }, + radius: 70.0, + material: Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: None, + }), + }); objects.add(boundary.clone()); - objects.add(Arc::new(ConstantMedium::new(boundary.clone(), 0.2, Arc::new(SolidColor::from_color(Color { x: 0.2, y: 0.4, z: 0.9 }))))); - let boundary = Arc::new(Sphere { center: Point3 { x: 0.0, y: 0.0, z: 0.0 }, radius: 5000.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) }); - objects.add(Arc::new(ConstantMedium::new(boundary.clone(), 0.0001, Arc::new(SolidColor::from_color(Color { x: 1.0, y: 1.0, z: 1.0 }))))); - - let emat = Arc::new(Lambertian { albedo: Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec())) }); - objects.add(Arc::new(Sphere { center: Point3 { x: 400.0, y: 200.0, z: 400.0 }, radius: 100.0, material: emat })); - let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(0.1)) }); - objects.add(Arc::new(Sphere { center: Point3 { x: 220.0, y: 280.0, z: 300.0 }, radius: 80.0, material: pertext })); + objects.add(Arc::new(ConstantMedium::new( + boundary.clone(), + 0.2, + Arc::new(SolidColor::from_color(Color { + x: 0.2, + y: 0.4, + z: 0.9, + })), + ))); + let boundary = Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + radius: 5000.0, + material: Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: None, + }), + }); + objects.add(Arc::new(ConstantMedium::new( + boundary.clone(), + 0.0001, + Arc::new(SolidColor::from_color(Color { + x: 1.0, + y: 1.0, + z: 1.0, + })), + ))); + + let emat = Arc::new(Lambertian { + albedo: Arc::new(ImageTexture::from_bmp_data( + &include_bytes!("../res/earthmap.bmp").to_vec(), + )), + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 400.0, + y: 200.0, + z: 400.0, + }, + radius: 100.0, + material: emat, + })); + let pertext = Arc::new(Lambertian { + albedo: Arc::new(NoiseTexture::new(0.1)), + }); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 220.0, + y: 280.0, + z: 300.0, + }, + radius: 80.0, + material: pertext, + })); let mut boxes_2 = HittableList::new(); - let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 })); + let white = Arc::new(Lambertian::from_color(Color { + x: 0.73, + y: 0.73, + z: 0.73, + })); for _ in 0..1000 { - boxes_2.add(Arc::new(Sphere { center: Point3::random_in_range(0.0, 165.0), radius: 10.0, material: white.clone() })); + boxes_2.add(Arc::new(Sphere { + center: Point3::random_in_range(0.0, 165.0), + radius: 10.0, + material: white.clone(), + })); } - objects.add(Arc::new(Translate { hittable: Arc::new(RotateY::new(Arc::new(BVHNode::new(&boxes_2, 0.0, 1.0)), 15.0)), offset: Vec3 { x: -100.0, y: 270.0, z: 395.0 } })); - (Arc::new(objects), Point3 { x: 478.0, y: 278.0, z: -600.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new()) + objects.add(Arc::new(Translate { + hittable: Arc::new(RotateY::new( + Arc::new(BVHNode::new(&boxes_2, 0.0, 1.0)), + 15.0, + )), + offset: Vec3 { + x: -100.0, + y: 270.0, + z: 395.0, + }, + })); + ( + Arc::new(objects), + Point3 { + x: 478.0, + y: 278.0, + z: -600.0, + }, + Point3 { + x: 278.0, + y: 278.0, + z: 0.0, + }, + 40.0, + 0.0, + Color::new(), + ) } fn test_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); //let earth_texture = Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec())); //let earth_surface = Arc::new(Lambertian { albedo: earth_texture }); - let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) }); - objects.add(Arc::new(XZRect { material: pertext, x0: -f64::INFINITY, x1: f64::INFINITY, z0: -f64::INFINITY, z1: f64::INFINITY, k: 0.0 })); + let pertext = Arc::new(Lambertian { + albedo: Arc::new(NoiseTexture::new(4.0)), + }); + objects.add(Arc::new(XZRect { + material: pertext, + x0: -f64::INFINITY, + x1: f64::INFINITY, + z0: -f64::INFINITY, + z1: f64::INFINITY, + k: 0.0, + })); //(Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) - (Arc::new(objects), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) + ( + Arc::new(objects), + Point3 { + x: 13.0, + y: 2.0, + z: 3.0, + }, + Point3::new(), + 20.0, + 0.0, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } fn triangle_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) { let mut objects = HittableList::new(); - let checker = Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 })); + let checker = Arc::new(CheckerTexture::from_colors( + Color { + x: 0.2, + y: 0.3, + z: 0.1, + }, + Color { + x: 0.9, + y: 0.9, + z: 0.9, + }, + )); let ground_material = Arc::new(Lambertian { albedo: checker }); - objects.add(Arc::new(Sphere{ center: Point3 { x: 0.0, y: -1001.0, z: 0.0 }, radius: 1000.0, material: ground_material })); + objects.add(Arc::new(Sphere { + center: Point3 { + x: 0.0, + y: -1001.0, + z: 0.0, + }, + radius: 1000.0, + material: ground_material, + })); //let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) }); //let pertext = Arc::new(Lambertian { albedo: Arc::new(SolidColor::from_color(Color {x: 0.0, y: 0.0, z: 0.0}) ) }); //objects.add(Arc::new(Triangle { material: Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.0 }), v0 : Vec3::new(), v1: Vec3 { x: 0.0, y: 0.0, z: 1.0 }, v2: Vec3 { x: 0.0, y: 1.0, z: 0.5 } })); - let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }))); + let monkey = Arc::new(Model::from_obj( + include_str!("../res/monkey.obj"), + Arc::new(Dielectric { + index_of_refraction: 1.5, + attenuation: Some(DielectricAttenuation { + albedo: Color { + x: 0.5, + y: 0.5, + z: 0.8, + }, + constant: 0.8, + }), + }), + )); // let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.5 }))); let monkey = Arc::new(RotateX::new(monkey, 45.0)); let monkey = Arc::new(RotateZ::new(monkey, 45.0)); objects.add(monkey); //(Arc::new(objects), Point3 { x: 5.0, y: 5.0, z: 5.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) - (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 5.0, y: 5.0, z: 5.0}, Point3 { x: 0.0, y: 0.0, z: 0.0}, 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 }) + ( + Arc::new(BVHNode::new(&objects, 0.0, 1.0)), + Point3 { + x: 5.0, + y: 5.0, + z: 5.0, + }, + Point3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, + 20.0, + 0.0, + Color { + x: 0.7, + y: 0.8, + z: 1.0, + }, + ) } diff --git a/src/texture/checker_texture.rs b/src/texture/checker_texture.rs index 385017b..d10166e 100644 --- a/src/texture/checker_texture.rs +++ b/src/texture/checker_texture.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use super::{Texture, SolidColor}; +use super::{SolidColor, Texture}; use crate::{vec3::Color, vec3::Point3}; pub struct CheckerTexture { diff --git a/src/texture/image_texture.rs b/src/texture/image_texture.rs index 763c3f0..d90b9b6 100644 --- a/src/texture/image_texture.rs +++ b/src/texture/image_texture.rs @@ -50,8 +50,12 @@ impl Texture for ImageTexture { let mut i = (u * self.width as f64) as usize; let mut j = (v * self.height as f64) as usize; - if i >= self.width { i = self.width - 1 }; - if j >= self.height { j = self.height - 1 }; + if i >= self.width { + i = self.width - 1 + }; + if j >= self.height { + j = self.height - 1 + }; let color_scale = 1.0 / 255.0; let pixel = j * self.bytes_per_scanline + i * BYTES_PER_PIXEL; Color { diff --git a/src/texture/noise_texture.rs b/src/texture/noise_texture.rs index 92ac166..7fe3cdb 100644 --- a/src/texture/noise_texture.rs +++ b/src/texture/noise_texture.rs @@ -1,4 +1,4 @@ -use super::{Texture, perlin::Perlin}; +use super::{perlin::Perlin, Texture}; use crate::{vec3::Color, vec3::Point3}; pub struct NoiseTexture { @@ -17,6 +17,11 @@ impl NoiseTexture { impl Texture for NoiseTexture { fn value(&self, _: f64, _: f64, p: &Point3) -> Color { - Color { x: 1.0, y: 1.0, z: 1.0 } * 0.5 * (1.0 + (self.scale * p.z + 10.0 * self.noise.turb(p, 7)).sin()) + Color { + x: 1.0, + y: 1.0, + z: 1.0, + } * 0.5 + * (1.0 + (self.scale * p.z + 10.0 * self.noise.turb(p, 7)).sin()) } } diff --git a/src/texture/perlin.rs b/src/texture/perlin.rs index 43d8f64..a796a43 100644 --- a/src/texture/perlin.rs +++ b/src/texture/perlin.rs @@ -1,4 +1,4 @@ -use crate::vec3::{Vec3, Point3}; +use crate::vec3::{Point3, Vec3}; const POINT_COUNT: usize = 256; @@ -55,7 +55,8 @@ impl Perlin { ^ self.perm_z.get(((k + dk as i32) & 255) as usize).unwrap()) as usize, ) - .unwrap().clone(); + .unwrap() + .clone(); } } } @@ -73,11 +74,15 @@ impl Perlin { let i_f = i as f64; let j_f = j as f64; let k_f = k as f64; - let weight_v = Vec3 { x: u - i_f, y: v - j_f, z: w - k_f }; - accum += (i_f * uu + (1.0 - i_f) * (1.0 - uu)) * - (j_f * vv + (1.0 - j_f) * (1.0 - vv)) * - (k_f * ww + (1.0 - k_f) * (1.0 - ww)) * - c[i][j][k].dot(&weight_v); + let weight_v = Vec3 { + x: u - i_f, + y: v - j_f, + z: w - k_f, + }; + accum += (i_f * uu + (1.0 - i_f) * (1.0 - uu)) + * (j_f * vv + (1.0 - j_f) * (1.0 - vv)) + * (k_f * ww + (1.0 - k_f) * (1.0 - ww)) + * c[i][j][k].dot(&weight_v); } } } diff --git a/src/texture/solid_color.rs b/src/texture/solid_color.rs index 3af46ca..1bbc463 100644 --- a/src/texture/solid_color.rs +++ b/src/texture/solid_color.rs @@ -7,9 +7,7 @@ pub struct SolidColor { impl SolidColor { pub fn from_color(color_value: Color) -> Self { - Self { - color_value, - } + Self { color_value } } } diff --git a/src/vec3.rs b/src/vec3.rs index 8525fdd..e2f253a 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -88,7 +88,7 @@ impl Vec3 { if p.length_squared() < 1.0 { return p; } - }; + } } pub fn random_unit_vector() -> Vec3 { @@ -98,8 +98,8 @@ impl Vec3 { pub fn random_in_unit_disk() -> Vec3 { loop { let p = Vec3 { - x: 2.0 * rand::random::<f64>() -1.0, - y: 2.0 * rand::random::<f64>() -1.0, + x: 2.0 * rand::random::<f64>() - 1.0, + y: 2.0 * rand::random::<f64>() - 1.0, z: 0.0, }; if p.length_squared() < 1.0 { @@ -166,7 +166,7 @@ impl<'a> Iterator for Vec3Iterator<'a> { } } -impl_op_ex!(- |a: &Vec3| -> Vec3 { +impl_op_ex!(-|a: &Vec3| -> Vec3 { Vec3 { x: -a.x, y: -a.y, |