Fixed bug in kdtree that this uncovered. Marked Hit and it's dependencies as needing to implement the Debug trait.
100 lines
3.0 KiB
Rust
100 lines
3.0 KiB
Rust
use std::f32::{consts::PI, MAX, MIN};
|
|
|
|
use crate::{
|
|
aabb::AABB,
|
|
hitable::{Hit, HitRecord},
|
|
ray::Ray,
|
|
vec3::Vec3,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct RotateY<H>
|
|
where
|
|
H: Hit,
|
|
{
|
|
hitable: H,
|
|
sin_theta: f32,
|
|
cos_theta: f32,
|
|
bbox: Option<AABB>,
|
|
}
|
|
|
|
impl<H> RotateY<H>
|
|
where
|
|
H: Hit,
|
|
{
|
|
pub fn new(hitable: H, angle: f32) -> RotateY<H> {
|
|
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<H> Hit for RotateY<H>
|
|
where
|
|
H: Hit,
|
|
{
|
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
|
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<AABB> {
|
|
self.bbox.clone()
|
|
}
|
|
}
|