140 lines
4.5 KiB
Rust
140 lines
4.5 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::{
|
|
aabb::AABB,
|
|
cuboid::Cuboid,
|
|
hitable::{Hit, HitRecord},
|
|
material::Material,
|
|
ray::Ray,
|
|
vec3::Vec3,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct Glowybox {
|
|
p_min: Vec3,
|
|
p_max: Vec3,
|
|
main: Cuboid,
|
|
edges: [Cuboid; 12],
|
|
}
|
|
|
|
impl Glowybox {
|
|
// This clippy doesn't work right with Arc.
|
|
#[allow(clippy::needless_pass_by_value)]
|
|
pub fn new(
|
|
p_min: Vec3,
|
|
p_max: Vec3,
|
|
edge_thickness: f32,
|
|
main_material: Arc<dyn Material>,
|
|
edge_material: Arc<dyn Material>,
|
|
) -> Glowybox {
|
|
assert!(p_min.x < p_max.x);
|
|
assert!(p_min.y < p_max.y);
|
|
assert!(p_min.z < p_max.z);
|
|
let main = Cuboid::new(p_min, p_max, main_material);
|
|
// Top edges
|
|
let ht = edge_thickness / 2.;
|
|
let edges = [
|
|
// Top edges
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_max.y - ht, p_min.z - ht].into(),
|
|
[p_min.x + ht, p_max.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_max.y - ht, p_min.z - ht].into(),
|
|
[p_max.x + ht, p_max.y + ht, p_min.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_max.x - ht, p_max.y - ht, p_min.z - ht].into(),
|
|
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_max.y - ht, p_max.z - ht].into(),
|
|
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
// Bottom edges
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
|
|
[p_min.x + ht, p_min.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
|
|
[p_max.x + ht, p_min.y + ht, p_min.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_max.x - ht, p_min.y - ht, p_min.z - ht].into(),
|
|
[p_max.x + ht, p_min.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_min.y - ht, p_max.z - ht].into(),
|
|
[p_max.x + ht, p_min.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
// Middle edges
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_min.y - ht, p_min.z - ht].into(),
|
|
[p_min.x + ht, p_max.y + ht, p_min.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_min.x - ht, p_min.y - ht, p_max.z - ht].into(),
|
|
[p_min.x + ht, p_max.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_max.x - ht, p_min.y - ht, p_min.z - ht].into(),
|
|
[p_max.x + ht, p_max.y + ht, p_min.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
Cuboid::new(
|
|
[p_max.x - ht, p_min.y - ht, p_max.z - ht].into(),
|
|
[p_max.x + ht, p_max.y + ht, p_max.z + ht].into(),
|
|
Arc::clone(&edge_material),
|
|
),
|
|
];
|
|
let p_min = [p_min.x - ht, p_min.y - ht, p_min.z - ht].into();
|
|
let p_max = [p_max.x + ht, p_max.y + ht, p_max.z + ht].into();
|
|
Glowybox {
|
|
p_min,
|
|
p_max,
|
|
main,
|
|
edges,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Hit for Glowybox {
|
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
|
let mut edge_hit = None;
|
|
for edge in &self.edges {
|
|
if let Some(hit) = edge.hit(r, t_min, t_max) {
|
|
edge_hit = Some(hit);
|
|
break;
|
|
}
|
|
}
|
|
let main_hit = self.main.hit(r, t_min, t_max);
|
|
match (edge_hit, main_hit) {
|
|
(Some(ehit), Some(mhit)) => {
|
|
if mhit.t < ehit.t {
|
|
Some(mhit)
|
|
} else {
|
|
Some(ehit)
|
|
}
|
|
}
|
|
(Some(ehit), None) => Some(ehit),
|
|
(None, Some(mhit)) => Some(mhit),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
|
Some(AABB::new(self.p_min, self.p_max))
|
|
}
|
|
}
|