use std::f32::{consts::PI, MAX, MIN}; use crate::{ aabb::AABB, hitable::{Hit, HitRecord}, ray::Ray, vec3::Vec3, }; #[derive(Debug)] pub struct RotateY where H: Hit, { hitable: H, sin_theta: f32, cos_theta: f32, bbox: Option, } impl RotateY where H: Hit, { pub fn new(hitable: H, angle: f32) -> RotateY { let radians = PI / 180. * angle; let sin_theta = radians.sin(); let cos_theta = radians.cos(); let mut min = vec![MAX, MAX, MAX]; let mut max = vec![MIN, MIN, MIN]; let bbox = hitable.bounding_box(0., 1.).unwrap(); for i in 0..2 { for j in 0..2 { for k in 0..2 { let x = i as f32 * bbox.max().x + (1 - i) as f32 * bbox.min().x; let y = j as f32 * bbox.max().y + (1 - j) as f32 * bbox.min().y; let z = k as f32 * bbox.max().z + (1 - k) as f32 * bbox.min().z; let new_x = cos_theta * x + sin_theta * z; let new_z = -sin_theta * x + cos_theta * z; let tester = Vec3::new(new_x, y, new_z); for c in 0..3 { if tester[c] > max[c] { max[c] = tester[c]; } if tester[c] < min[c] { min[c] = tester[c]; } } } } } RotateY { hitable, sin_theta, cos_theta, bbox: Some(AABB::new( Vec3::new(min[0], min[1], min[2]), Vec3::new(max[0], max[1], max[2]), )), } } } impl Hit for RotateY where H: Hit, { fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let origin = Vec3::new( self.cos_theta * r.origin[0] - self.sin_theta * r.origin[2], r.origin.y, self.sin_theta * r.origin[0] + self.cos_theta * r.origin[2], ); let direction = Vec3::new( self.cos_theta * r.direction[0] - self.sin_theta * r.direction[2], r.direction.y, self.sin_theta * r.direction[0] + self.cos_theta * r.direction[2], ); let rotated_r = Ray::new(origin, direction, r.time); if let Some(rec) = self.hitable.hit(rotated_r, t_min, t_max) { let p = Vec3::new( self.cos_theta * rec.p[0] + self.sin_theta * rec.p[2], rec.p[1], -self.sin_theta * rec.p[0] + self.cos_theta * rec.p[2], ); let normal = Vec3::new( self.cos_theta * rec.normal[0] + self.sin_theta * rec.normal[2], rec.normal[1], -self.sin_theta * rec.normal[0] + self.cos_theta * rec.normal[2], ); return Some(HitRecord { p, normal, ..rec }); } None } fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option { self.bbox.clone() } }