summaryrefslogtreecommitdiff
path: root/src/object.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/object.rs')
-rw-r--r--src/object.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/object.rs b/src/object.rs
new file mode 100644
index 0000000..ff965f0
--- /dev/null
+++ b/src/object.rs
@@ -0,0 +1,109 @@
+use crate::calculus::calculus::{Point3, Ray, Vec3};
+
+#[derive(Clone)]
+pub struct HitRecord {
+ pub position: Point3,
+ pub normal: Vec3,
+ pub t: f32,
+ pub front_face: bool,
+}
+
+impl Default for HitRecord {
+ fn default() -> Self {
+ Self {
+ position: Point3 {x:0.0, y:0.0, z:0.0},
+ normal: Vec3 {x:0.0, y:0.0, z:0.0},
+ t: 0.0,
+ front_face: false,
+ }
+ }
+}
+
+impl HitRecord {
+ pub fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) {
+ self.front_face = r.direction.dot_prod(&outward_normal) < 0.0;
+ self.normal = if self.front_face { outward_normal } else { outward_normal.scalar_mul(-1.0) };
+ }
+}
+
+pub trait Hittable {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool;
+}
+
+pub struct Sphere {
+ center: Point3,
+ radius: f32,
+}
+
+impl Sphere {
+ pub fn new(center: Vec3, radius: f32) -> Self {
+ let r = f32::max(0.0, radius);
+ Self { center, radius }
+ }
+}
+
+impl Hittable for Sphere {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool {
+ let oc = self.center.sub(&r.origin);
+ let a = r.direction.mag_sqr();
+ let h = r.direction.dot_prod(&oc);
+ let c = oc.mag_sqr() - self.radius * self.radius;
+ let discriminant = h * h - a * c;
+ if discriminant < 0.0 {
+ return false;
+ }
+
+ let sqrtd = discriminant.sqrt();
+
+ let mut root = (h - sqrtd) / a;
+ if root <= ray_tmin || ray_tmax <= root {
+ root = (h + sqrtd) / a;
+ if root <= ray_tmin || ray_tmax <= root {
+ return false;
+ }
+ }
+
+ rec.t = root;
+ rec.position = r.at(rec.t);
+ let outward_normal = rec.normal
+ .sub(&self.center)
+ .scalar_mul(1.0 / self.radius);
+ rec.set_face_normal(r, outward_normal);
+
+ true
+ }
+}
+
+pub struct HittableList {
+ objects: Vec<Box<dyn Hittable>>,
+}
+
+impl HittableList {
+ pub fn new() -> Self {
+ Self { objects: vec![] }
+ }
+
+ pub fn push<T: Hittable + 'static>(&mut self, object: T) {
+ self.objects.push(Box::new(object));
+ }
+}
+
+impl Hittable for HittableList {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool {
+ let mut temp_rec = HitRecord::default();
+ let mut hit_anything = false;
+ let mut closest_so_far = ray_tmax;
+
+ self.objects.iter().for_each(
+ |object| {
+ if object.hit(r, ray_tmin, closest_so_far, &mut temp_rec) {
+ hit_anything = true;
+ closest_so_far = temp_rec.t;
+ *rec = temp_rec.clone();
+ }
+ }
+ );
+
+ hit_anything
+ }
+} \ No newline at end of file