diff --git a/src/hittable.rs b/src/hittable.rs index 141be51..596856c 100644 --- a/src/hittable.rs +++ b/src/hittable.rs @@ -19,6 +19,30 @@ pub struct HitRecord<'material> { pub material: &'material Arc } +impl<'material> HitRecord<'material> { + pub fn normalized(&mut self, ray: &Ray) { + let dot = ray.direction().dot(&self.normal); + let front_face = dot < 0.0; + let normal = if front_face { self.normal } else { -self.normal }; + self.normal = normal; + self.front_face = front_face; + } + /*pub fn normalized(& self) -> Self { + let dot = ray.direction().dot(self.normal); + let front_face = dot < 0.0; + let normal = if front_face { self.normal } else { -self.normal }; + HitRecord { + point: self.point, + normal, + t: self.t, + u: self.u, + v: self.v, + front_face, + material: self.material + } + }*/ +} + pub trait Hittable { fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option; fn bounding_box(&self, time0: f64, time1: f64) -> Option; @@ -74,19 +98,18 @@ impl Hittable for Sphere { } let point = ray.at(root); let normal = (point - self.center) / self.radius; - let dot = ray.direction().dot(&normal); - let front_face = dot < 0.0; let (u, v) = Sphere::uv(&normal); - let normal = if front_face { normal } else { -normal }; - Some(HitRecord { + let mut rec = HitRecord { point, normal, t: root, u, v, - front_face, + front_face: false, // Will be set during normalied() material: &self.material - }) + }; + rec.normalized(ray); + Some(rec) } fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { let s = Vec3::new(self.radius, self.radius, self.radius); diff --git a/src/main.rs b/src/main.rs index 0d430c8..b7a9e57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,8 @@ use crate::noise::NoiseTexture; use crate::perlin::Perlin; use crate::texture::CheckerTexture; use crate::rect::{Plane, Rect2D}; +use crate::rotate_y::RotateY; +use crate::translate::Translate; mod vec3; mod ray; @@ -32,10 +34,12 @@ mod noise; mod image_texture; mod rect; mod cuboid; +mod translate; +mod rotate_y; // Image const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0; -const IMAGE_WIDTH: usize = 600; +const IMAGE_WIDTH: usize = 400; const SAMPLES_PER_PIXEL: i32 = 100; const MAX_DEPTH: i32 = 50; @@ -113,16 +117,32 @@ fn cornell_box() -> Scene { ))); // Boxes - world.push(Arc::new(Cuboid::new( - Point3::new(130.0, 0.0, 65.0), - Point3::new(295.0, 165.0, 230.0), - white.clone() - ))); - world.push(Arc::new(Cuboid::new( - Point3::new(265.0, 0.0, 295.0), - Point3::new(430.0, 330.0, 460.0), - white.clone() - ))); + let rotated1 = RotateY::new( + Cuboid::new( + Point3::new(0.0, 0.0, 0.0), + Point3::new(165.0, 330.0, 165.0), + white.clone() + ), + 15.0 + ); + let box1 = Translate::new( + rotated1, + Vec3::new(265.0, 0.0, 295.0) + ); + world.push(Arc::new(box1)); + let rotated2 = RotateY::new( + Cuboid::new( + Point3::new(0.0, 0.0, 0.0), + Point3::new(165.0, 165.0, 165.0), + white.clone() + ), + -18.0 + ); + let box2 = Translate::new( + rotated2, + Vec3::new(130.0,0.0,65.0) + ); + world.push(Arc::new(box2)); let look_from = Point3::new(278.0, 278.0, -800.0); diff --git a/src/translate.rs b/src/translate.rs new file mode 100644 index 0000000..161185f --- /dev/null +++ b/src/translate.rs @@ -0,0 +1,48 @@ +use crate::hittable::{HitRecord, Hittable}; +use crate::{Aabb, Ray, Vec3}; + +pub struct Translate { + hittable: H, + offset: Vec3 +} + +impl Translate { + pub fn new(hittable: H, offset: Vec3) -> Self { + Self { hittable, offset } + } +} + +impl Hittable for Translate { + fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { + let moved_ray = Ray::new( + ray.origin() - self.offset, + ray.direction(), + ray.time()); + match &self.hittable.hit(&moved_ray, t_min, t_max) { + Some(hit_record) => { + let mut hr = HitRecord { + point: hit_record.point, + material: hit_record.material, + front_face: hit_record.front_face, // Maybe need to calc normal and front_face again? + normal: hit_record.normal, + t: hit_record.t, + u: hit_record.u, + v: hit_record.v + }; + hr.normalized(ray); + Some(hr) + } + _ => None + } + } + + fn bounding_box(&self, time0: f64, time1: f64) -> Option { + match &self.hittable.bounding_box(time0, time1) { + Some(bounding_box) => Some(Aabb { + minimum: bounding_box.minimum + self.offset, + maximum: bounding_box.maximum + self.offset, + }), + _ => None + } + } +} diff --git a/src/vec3.rs b/src/vec3.rs index e4a9813..c83195c 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Formatter}; -use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, Index, MulAssign}; +use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, Index, MulAssign, IndexMut}; use rand::distributions::{Distribution, Uniform}; #[derive(Debug, Clone, Copy)] @@ -295,6 +295,16 @@ impl Index for Vec3 { } } } +impl IndexMut for Vec3 { + fn index_mut(&mut self, index: i32) -> &mut f64{ + match index { + 0 => &mut self.x, + 1 => &mut self.y, + 2 => &mut self.z, + _ => panic!("Unknown index") + } + } +} impl Index for Vec3 { type Output = f64; fn index(&self, index: usize) -> &Self::Output {