aboutsummaryrefslogtreecommitdiff
path: root/src/hittable/sphere.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hittable/sphere.rs')
-rw-r--r--src/hittable/sphere.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/hittable/sphere.rs b/src/hittable/sphere.rs
new file mode 100644
index 0000000..783b788
--- /dev/null
+++ b/src/hittable/sphere.rs
@@ -0,0 +1,61 @@
+use std::sync::Arc;
+use std::f64::consts;
+
+use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, vec3::Vec3};
+use crate::ray::Ray;
+use crate::vec3::Point3;
+
+pub struct Sphere {
+ pub center: Point3,
+ pub radius: f64,
+ pub material: Arc<dyn Material>,
+}
+
+impl Sphere {
+ pub fn get_sphere_uv(p: &Point3, u: &mut f64, v: &mut f64) {
+ let theta = (-p.y).acos();
+ let phi = -p.z.atan2(p.x) + consts::PI;
+
+ *u = phi / (2.0 * consts::PI);
+ *v = theta / consts::PI;
+ }
+}
+
+impl Hittable for Sphere {
+ fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
+ let oc = &ray.origin - &self.center;
+ let a = ray.direction.length_squared();
+ let half_b = oc.dot(&ray.direction);
+ let c = oc.length_squared() - self.radius * self.radius;
+ let discriminant = half_b * half_b - a * c;
+ if discriminant < 0.0 {
+ return None;
+ }
+
+ let sqrtd = discriminant.sqrt();
+ // Find the nearest root that lies within acceptable range
+ let mut root = (-half_b - sqrtd) / a;
+ if root < t_min || t_max < root {
+ root = (-half_b + sqrtd) / a;
+ if root < t_min || t_max < root {
+ return None;
+ }
+ }
+
+ let mut hit_record = HitRecord::new();
+ hit_record.t = root;
+ hit_record.p = ray.at(hit_record.t);
+ let outward_normal = (&hit_record.p - &self.center) / self.radius;
+ hit_record.set_face_normal(ray, &outward_normal);
+ Self::get_sphere_uv(&outward_normal, &mut hit_record.u, &mut hit_record.v);
+ hit_record.material = Some(self.material.clone());
+ Some(hit_record)
+ }
+
+ fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
+ Some(AABB {
+ minimum: &self.center - Vec3 { x: self.radius, y: self.radius, z: self.radius },
+ maximum: &self.center + Vec3 { x: self.radius, y: self.radius, z: self.radius },
+ })
+ }
+}