89 lines
2.9 KiB
Rust
89 lines
2.9 KiB
Rust
use std::sync::Arc;
|
|
use crate::hittable::{HitRecord, Hittable};
|
|
use crate::{Aabb, Material, Point3, Ray, Vec3};
|
|
|
|
pub enum Plane {
|
|
XY,
|
|
XZ,
|
|
YZ
|
|
}
|
|
|
|
pub struct Rect2D {
|
|
plane: Plane,
|
|
a0: f64,
|
|
a1: f64,
|
|
b0: f64,
|
|
b1: f64,
|
|
k: f64,
|
|
material: Arc<Material>
|
|
}
|
|
|
|
impl Rect2D {
|
|
pub fn new(plane: Plane, a0: f64, a1: f64, b0: f64, b1: f64, k: f64, material: Arc<Material>) -> Self {
|
|
Self { plane, a0, a1, b0, b1, k, material }
|
|
}
|
|
}
|
|
|
|
impl Hittable for Rect2D {
|
|
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
|
let t = match &self.plane {
|
|
Plane::XY => (self.k - ray.origin().z()) / ray.direction().z(),
|
|
Plane::XZ => (self.k - ray.origin().y()) / ray.direction().y(),
|
|
Plane::YZ => (self.k - ray.origin().x()) / ray.direction().x(),
|
|
};
|
|
let (a, b) = match &self.plane {
|
|
Plane::XY => (
|
|
ray.origin().x() + t * ray.direction().x(),
|
|
ray.origin().y() + t * ray.direction().y()),
|
|
Plane::XZ => (
|
|
ray.origin().x() + t * ray.direction().x(),
|
|
ray.origin().z() + t * ray.direction().z()),
|
|
Plane::YZ => (
|
|
ray.origin().y() + t * ray.direction().y(),
|
|
ray.origin().z() + t * ray.direction().z()),
|
|
};
|
|
if t < t_min || t > t_max {
|
|
return None;
|
|
}
|
|
if a < self.a0 || a > self.a1 || b < self.b0 || b > self.b1 {
|
|
return None;
|
|
}
|
|
let normal = match &self.plane {
|
|
Plane::XY => Vec3::new(0.0, 0.0, 1.0),
|
|
Plane::XZ => Vec3::new(0.0, 1.0, 0.0),
|
|
Plane::YZ => Vec3::new(1.0, 0.0, 0.0),
|
|
};
|
|
let dot = ray.direction().dot(&normal);
|
|
let front_face = dot < 0.0;
|
|
let normal = if front_face { normal } else { -normal };
|
|
Some(HitRecord {
|
|
point: ray.at(t),
|
|
normal,
|
|
t,
|
|
u: (a-self.a0)/(self.a1 -self.a0),
|
|
v: (b-self.b0)/(self.b1 -self.b0),
|
|
front_face,
|
|
material: &self.material
|
|
})
|
|
}
|
|
|
|
fn bounding_box(&self, _time0: f64, _time1: f64) -> Option<Aabb> {
|
|
// The bounding box must have non-zero width in each dimension, so pad the Z
|
|
// dimension a small amount.
|
|
match &self.plane {
|
|
Plane::XY => Some(Aabb {
|
|
minimum: Point3::new(self.a0, self.b0, self.k-0.0001),
|
|
maximum: Point3::new(self.a1, self.b1, self.k+0.0001),
|
|
}),
|
|
Plane::XZ=> Some(Aabb {
|
|
minimum: Point3::new(self.a0, self.k-0.0001, self.b0),
|
|
maximum: Point3::new(self.a1, self.k+0.0001, self.b1),
|
|
}),
|
|
Plane::YZ => Some(Aabb {
|
|
minimum: Point3::new(self.k-0.0001, self.a0, self.b0),
|
|
maximum: Point3::new(self.k+0.0001, self.a1, self.b1),
|
|
})
|
|
}
|
|
}
|
|
}
|