aboutsummaryrefslogtreecommitdiff
path: root/src/hittable/instance
diff options
context:
space:
mode:
authorlamp2023-03-05 21:45:56 +0000
committerlamp2023-03-05 21:45:56 +0000
commit78ddaff5855bf8446adef9e18eb0d7b7ddcee52a (patch)
tree0d0e93cfa28751a2f96518eeb231cf715958e1fa /src/hittable/instance
init
Diffstat (limited to 'src/hittable/instance')
-rw-r--r--src/hittable/instance/mod.rs10
-rw-r--r--src/hittable/instance/moving.rs40
-rw-r--r--src/hittable/instance/rotate_x.rs83
-rw-r--r--src/hittable/instance/rotate_y.rs83
-rw-r--r--src/hittable/instance/rotate_z.rs83
-rw-r--r--src/hittable/instance/translate.rs27
6 files changed, 326 insertions, 0 deletions
diff --git a/src/hittable/instance/mod.rs b/src/hittable/instance/mod.rs
new file mode 100644
index 0000000..d40dcc5
--- /dev/null
+++ b/src/hittable/instance/mod.rs
@@ -0,0 +1,10 @@
+mod moving;
+pub use moving::Moving;
+mod rotate_y;
+pub use rotate_y::RotateY;
+mod rotate_x;
+pub use rotate_x::RotateX;
+mod rotate_z;
+pub use rotate_z::RotateZ;
+mod translate;
+pub use translate::Translate;
diff --git a/src/hittable/instance/moving.rs b/src/hittable/instance/moving.rs
new file mode 100644
index 0000000..418fdbb
--- /dev/null
+++ b/src/hittable/instance/moving.rs
@@ -0,0 +1,40 @@
+use std::sync::Arc;
+
+use crate::{ray::Ray, vec3::Vec3};
+use crate::hittable::{HitRecord, Hittable, AABB};
+
+pub struct Moving {
+ pub hittable: Arc<dyn Hittable>,
+ pub offset_start: Vec3,
+ pub offset_end: Vec3,
+ pub time_start: f64,
+ pub time_end: f64,
+}
+
+impl Moving {
+ fn offset_at(&self, time: f64) -> Vec3 {
+ &self.offset_start + ((time - self.time_start) / (self.time_end - self.time_start)) * (&self.offset_end - &self.offset_start)
+ }
+}
+
+impl Hittable for Moving {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let moved_ray = Ray { origin: &ray.origin - &self.offset_at(ray.time), direction: ray.direction.clone(), time: ray.time };
+ let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?;
+ hit_record.p += self.offset_at(ray.time).clone();
+ let normal = hit_record.normal.clone();
+ hit_record.set_face_normal(&moved_ray, &normal);
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, time_start: f64, time_end: f64) -> Option<AABB> {
+ let output_box = self.hittable.bounding_box(time_start, time_end)?;
+ Some(AABB {
+ minimum: &output_box.minimum + &self.offset_at(time_start),
+ maximum: &output_box.maximum + &self.offset_at(time_start),
+ }.surrounding_box(&AABB {
+ minimum: &output_box.minimum + &self.offset_at(time_end),
+ maximum: &output_box.maximum + &self.offset_at(time_end),
+ }))
+ }
+}
diff --git a/src/hittable/instance/rotate_x.rs b/src/hittable/instance/rotate_x.rs
new file mode 100644
index 0000000..4ebc04d
--- /dev/null
+++ b/src/hittable/instance/rotate_x.rs
@@ -0,0 +1,83 @@
+use std::sync::Arc;
+
+use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+
+pub struct RotateX {
+ hittable: Arc<dyn Hittable>,
+ sin_theta: f64,
+ cos_theta: f64,
+ aabb: Option<AABB>,
+}
+
+impl RotateX {
+ pub fn new(hittable: Arc<dyn Hittable>, angle: f64) -> Self {
+ let radians = degrees_to_radians(angle);
+ let sin_theta = radians.sin();
+ let cos_theta = radians.cos();
+ match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ Some(aabb) => {
+ let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
+ let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ for i in 0..2 {
+ for j in 0..2 {
+ for k in 0..2 {
+ let x = i as f64 * aabb.maximum.x + (1.0 - i as f64) * aabb.minimum.x;
+ let y = j as f64 * aabb.maximum.y + (1.0 - j as f64) * aabb.minimum.y;
+ let z = k as f64 * aabb.maximum.z + (1.0 - k as f64) * aabb.minimum.z;
+ let new_y = cos_theta * y + sin_theta * y;
+ let new_z = -sin_theta * y + cos_theta * z;
+
+ let tester = Vec3 { y: new_y, x, z: new_z };
+ for c in 0..3 {
+ *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ }
+ }
+ }
+ }
+ let aabb = AABB { minimum: min, maximum: max };
+
+ Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: Some(aabb),
+ }
+ }
+ }
+ }
+}
+
+impl Hittable for RotateX {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let mut origin = ray.origin.clone();
+ let mut direction = ray.direction.clone();
+
+ origin.y = self.cos_theta * ray.origin.y - self.sin_theta * ray.origin.z;
+ origin.z = self.sin_theta * ray.origin.y + self.cos_theta * ray.origin.z;
+
+ direction.y = self.cos_theta * ray.direction.y - self.sin_theta * ray.direction.z;
+ direction.z = self.sin_theta * ray.direction.y + self.cos_theta * ray.direction.z;
+
+ let rotated_ray = Ray { origin, direction, time: ray.time };
+ let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
+
+ let mut p = hit_record.p.clone();
+ let mut normal = hit_record.normal.clone();
+
+ p.y = self.cos_theta * hit_record.p.y+ self.sin_theta * hit_record.p.z;
+ p.z = -self.sin_theta * hit_record.p.y + self.cos_theta * hit_record.p.z;
+
+ normal.y = self.cos_theta * hit_record.normal.y + self.sin_theta * hit_record.normal.z;
+ normal.z = -self.sin_theta * hit_record.normal.y + self.cos_theta * hit_record.normal.z;
+
+ hit_record.p = p;
+ hit_record.set_face_normal(&ray, &normal);
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
+ self.aabb.clone()
+ }
+}
diff --git a/src/hittable/instance/rotate_y.rs b/src/hittable/instance/rotate_y.rs
new file mode 100644
index 0000000..8611616
--- /dev/null
+++ b/src/hittable/instance/rotate_y.rs
@@ -0,0 +1,83 @@
+use std::sync::Arc;
+
+use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+
+pub struct RotateY {
+ hittable: Arc<dyn Hittable>,
+ sin_theta: f64,
+ cos_theta: f64,
+ aabb: Option<AABB>,
+}
+
+impl RotateY {
+ pub fn new(hittable: Arc<dyn Hittable>, angle: f64) -> Self {
+ let radians = degrees_to_radians(angle);
+ let sin_theta = radians.sin();
+ let cos_theta = radians.cos();
+ match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ Some(aabb) => {
+ let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
+ let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ for i in 0..2 {
+ for j in 0..2 {
+ for k in 0..2 {
+ let x = i as f64 * aabb.maximum.x + (1.0 - i as f64) * aabb.minimum.x;
+ let y = j as f64 * aabb.maximum.y + (1.0 - j as f64) * aabb.minimum.y;
+ let z = k as f64 * aabb.maximum.z + (1.0 - k as f64) * aabb.minimum.z;
+ let new_x = cos_theta * x + sin_theta * z;
+ let new_z = -sin_theta * x + cos_theta * z;
+
+ let tester = Vec3 { x: new_x, y, z: new_z };
+ for c in 0..3 {
+ *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ }
+ }
+ }
+ }
+ let aabb = AABB { minimum: min, maximum: max };
+
+ Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: Some(aabb),
+ }
+ }
+ }
+ }
+}
+
+impl Hittable for RotateY {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let mut origin = ray.origin.clone();
+ let mut direction = ray.direction.clone();
+
+ origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.z;
+ origin.z = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.z;
+
+ direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.z;
+ direction.z = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.z;
+
+ let rotated_ray = Ray { origin, direction, time: ray.time };
+ let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
+
+ let mut p = hit_record.p.clone();
+ let mut normal = hit_record.normal.clone();
+
+ p.x = self.cos_theta * hit_record.p.x + self.sin_theta * hit_record.p.z;
+ p.z = -self.sin_theta * hit_record.p.x + self.cos_theta * hit_record.p.z;
+
+ normal.x = self.cos_theta * hit_record.normal.x + self.sin_theta * hit_record.normal.z;
+ normal.z = -self.sin_theta * hit_record.normal.x + self.cos_theta * hit_record.normal.z;
+
+ hit_record.p = p;
+ hit_record.set_face_normal(&ray, &normal);
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
+ self.aabb.clone()
+ }
+}
diff --git a/src/hittable/instance/rotate_z.rs b/src/hittable/instance/rotate_z.rs
new file mode 100644
index 0000000..119baca
--- /dev/null
+++ b/src/hittable/instance/rotate_z.rs
@@ -0,0 +1,83 @@
+use std::sync::Arc;
+
+use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+
+pub struct RotateZ {
+ hittable: Arc<dyn Hittable>,
+ sin_theta: f64,
+ cos_theta: f64,
+ aabb: Option<AABB>,
+}
+
+impl RotateZ {
+ pub fn new(hittable: Arc<dyn Hittable>, angle: f64) -> Self {
+ let radians = degrees_to_radians(angle);
+ let sin_theta = radians.sin();
+ let cos_theta = radians.cos();
+ match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ Some(aabb) => {
+ let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
+ let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ for i in 0..2 {
+ for j in 0..2 {
+ for k in 0..2 {
+ let x = i as f64 * aabb.maximum.x + (1.0 - i as f64) * aabb.minimum.x;
+ let y = j as f64 * aabb.maximum.y + (1.0 - j as f64) * aabb.minimum.y;
+ let z = k as f64 * aabb.maximum.z + (1.0 - k as f64) * aabb.minimum.z;
+ let new_x = cos_theta * x + sin_theta * y;
+ let new_y = -sin_theta * x + cos_theta * y;
+
+ let tester = Vec3 { x: new_x, z, y: new_y };
+ for c in 0..3 {
+ *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ }
+ }
+ }
+ }
+ let aabb = AABB { minimum: min, maximum: max };
+
+ Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: Some(aabb),
+ }
+ }
+ }
+ }
+}
+
+impl Hittable for RotateZ {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let mut origin = ray.origin.clone();
+ let mut direction = ray.direction.clone();
+
+ origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.y;
+ origin.y = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.y;
+
+ direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.y;
+ direction.y = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.y;
+
+ let rotated_ray = Ray { origin, direction, time: ray.time };
+ let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
+
+ let mut p = hit_record.p.clone();
+ let mut normal = hit_record.normal.clone();
+
+ p.x = self.cos_theta * hit_record.p.x + self.sin_theta * hit_record.p.y;
+ p.y = -self.sin_theta * hit_record.p.x + self.cos_theta * hit_record.p.y;
+
+ normal.x = self.cos_theta * hit_record.normal.x + self.sin_theta * hit_record.normal.y;
+ normal.y = -self.sin_theta * hit_record.normal.x + self.cos_theta * hit_record.normal.y;
+
+ hit_record.p = p;
+ hit_record.set_face_normal(&ray, &normal);
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
+ self.aabb.clone()
+ }
+}
diff --git a/src/hittable/instance/translate.rs b/src/hittable/instance/translate.rs
new file mode 100644
index 0000000..a9c8162
--- /dev/null
+++ b/src/hittable/instance/translate.rs
@@ -0,0 +1,27 @@
+use std::sync::Arc;
+
+use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, vec3::Vec3};
+
+pub struct Translate {
+ pub hittable: Arc<dyn Hittable>,
+ pub offset: Vec3,
+}
+
+impl Hittable for Translate {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let moved_ray = Ray { origin: &ray.origin - &self.offset, direction: ray.direction.clone(), time: ray.time };
+ let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?;
+ hit_record.p += self.offset.clone();
+ let normal = hit_record.normal.clone();
+ hit_record.set_face_normal(&moved_ray, &normal);
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, time_start: f64, time_end: f64) -> Option<AABB> {
+ let output_box = self.hittable.bounding_box(time_start, time_end)?;
+ Some(AABB {
+ minimum: &output_box.minimum + &self.offset,
+ maximum: &output_box.maximum + &self.offset,
+ })
+ }
+}