From 78ddaff5855bf8446adef9e18eb0d7b7ddcee52a Mon Sep 17 00:00:00 2001 From: lamp Date: Sun, 5 Mar 2023 21:45:56 +0000 Subject: init --- src/hittable/instance/mod.rs | 10 +++++ src/hittable/instance/moving.rs | 40 ++++++++++++++++++ src/hittable/instance/rotate_x.rs | 83 ++++++++++++++++++++++++++++++++++++++ src/hittable/instance/rotate_y.rs | 83 ++++++++++++++++++++++++++++++++++++++ src/hittable/instance/rotate_z.rs | 83 ++++++++++++++++++++++++++++++++++++++ src/hittable/instance/translate.rs | 27 +++++++++++++ 6 files changed, 326 insertions(+) create mode 100644 src/hittable/instance/mod.rs create mode 100644 src/hittable/instance/moving.rs create mode 100644 src/hittable/instance/rotate_x.rs create mode 100644 src/hittable/instance/rotate_y.rs create mode 100644 src/hittable/instance/rotate_z.rs create mode 100644 src/hittable/instance/translate.rs (limited to 'src/hittable/instance') 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, + 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 { + 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 { + 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, + sin_theta: f64, + cos_theta: f64, + aabb: Option, +} + +impl RotateX { + pub fn new(hittable: Arc, 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 { + 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 { + 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, + sin_theta: f64, + cos_theta: f64, + aabb: Option, +} + +impl RotateY { + pub fn new(hittable: Arc, 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 { + 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 { + 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, + sin_theta: f64, + cos_theta: f64, + aabb: Option, +} + +impl RotateZ { + pub fn new(hittable: Arc, 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 { + 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 { + 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, + pub offset: Vec3, +} + +impl Hittable for Translate { + fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { + 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 { + 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, + }) + } +} -- cgit v1.2.3