use crate::hittable::{HitRecord, Hittable}; use crate::{Aabb, Point3, Ray, Vec3}; pub struct RotateY { hittable: H, sin_theta: f64, cos_theta: f64, bounding_box: Option } impl RotateY { pub fn new(hittable: H, degrees: f64) -> Self { let radians = degrees.to_radians(); let sin_theta = radians.sin(); let cos_theta = radians.cos(); let mut bounding_box = hittable.bounding_box(0.0, 1.0); if let Some(bbox) = bounding_box { let mut min = Point3::new(f64::INFINITY, f64::INFINITY, f64::INFINITY); let mut max = Point3::new(f64::NEG_INFINITY, f64::NEG_INFINITY, f64::NEG_INFINITY); for i in 0..2 { for j in 0..2 { for k in 0..2 { let x = (i as f64)*bbox.maximum.x() + ((1 - i) as f64)*bbox.minimum.x(); let y = (i as f64)*bbox.maximum.y() + ((1 - j) as f64)*bbox.minimum.y(); let z = (i as f64)*bbox.maximum.z() + ((1 - k) as f64)*bbox.minimum.z(); let x = cos_theta * x + sin_theta * z; let z = -sin_theta * x + cos_theta * z; let tester = Vec3::new(x, y, z); for c in 0..3 { min[c] = min[c].min(tester[c]); max[c] = max[c].max(tester[c]); } } } } bounding_box = Some(Aabb { minimum: min, maximum: max }); } Self { hittable, sin_theta, cos_theta, bounding_box } } } impl Hittable for RotateY { fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { let mut origin = ray.origin(); let mut direction = ray.direction(); origin[0] = self.cos_theta * ray.origin()[0] - self.sin_theta*ray.origin()[2]; origin[2] = self.sin_theta * ray.origin()[0] + self.cos_theta*ray.origin()[2]; direction[0] = self.cos_theta * ray.direction()[0] - self.sin_theta*ray.direction()[2]; direction[2] = self.sin_theta * ray.direction()[0] + self.cos_theta*ray.direction()[2]; let rotated = Ray::new(origin, direction, ray.time()); match self.hittable.hit(&rotated, t_min, t_max) { Some(rec) => { let mut p = rec.point; let mut normal = rec.normal; p[0] = self.cos_theta*rec.point[0] + self.sin_theta * rec.point[2]; p[2] = -self.sin_theta*rec.point[0] + self.cos_theta * rec.point[2]; normal[0] = self.cos_theta*rec.normal[0] + self.sin_theta * rec.normal[2]; normal[2] = -self.sin_theta*rec.normal[0] + self.cos_theta * rec.normal[2]; let mut new_rec = HitRecord { point: p, normal, t: rec.t, u: rec.u, v: rec.v, front_face: rec.front_face, material: rec.material, }; new_rec.normalized(&rotated); Some(new_rec) }, _ => None } } fn bounding_box(&self, _time0: f64, _time1: f64) -> Option { self.bounding_box } }