From 1af881f36e46a07a182693c5ab756bb006903242 Mon Sep 17 00:00:00 2001 From: Alan Jian Date: Wed, 17 Jul 2024 15:28:09 +0800 Subject: [PATCH] feat: add sphere to shapes --- src/core.rs | 6 ++++++ src/main.rs | 21 ++++++--------------- src/shapes.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 src/shapes.rs diff --git a/src/core.rs b/src/core.rs index 4330378..ccd4684 100644 --- a/src/core.rs +++ b/src/core.rs @@ -14,3 +14,9 @@ impl Ray { self.orig + t * self.dir } } + +pub trait Intersect { + fn intersect(&self, _ray: &Ray) -> Option { + None + } +} diff --git a/src/main.rs b/src/main.rs index 60f60f2..9015e23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,22 @@ mod camera; mod cli; mod core; +mod shapes; use camera::Camera; use clap::Parser; use cli::{Cli, Size}; -use core::Ray; +use core::{Intersect, Ray}; use image::{Rgb, RgbImage}; use indicatif::ProgressBar; use nalgebra::{Point2, Point3, Vector3}; use palette::{LinSrgb, Srgb}; - -fn hit_sphere(center: Point3, radius: f64, ray: &Ray) -> Option { - let a = ray.dir.magnitude_squared(); - let b = (-2.0 * ray.dir).dot(&(center - ray.orig)); - let c = (center - ray.orig).magnitude_squared() - radius * radius; - let discriminant = b * b - 4.0 * a * c; - if discriminant < 0.0 { - return None; - } - Some((-b - discriminant.sqrt()) / (2.0 * a)) -} +use shapes::Sphere; fn ray_color(ray: &Ray) -> LinSrgb { - let sphere_center = Point3::new(0.0, 0.0, -1.0); - if let Some(t) = hit_sphere(sphere_center, 0.5, ray) { - let normal = (ray.at(t) - sphere_center).normalize(); + let sphere = Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5); + if let Some(t) = sphere.intersect(ray) { + let normal = (ray.at(t) - Point3::new(0.0, 0.0, -1.0)).normalize(); let normal = 0.5 * (normal + Vector3::new(1.0, 1.0, 1.0)); return LinSrgb::new(normal.x, normal.y, normal.z); } diff --git a/src/shapes.rs b/src/shapes.rs new file mode 100644 index 0000000..c5b0077 --- /dev/null +++ b/src/shapes.rs @@ -0,0 +1,26 @@ +use crate::{Intersect, Ray}; +use nalgebra::Point3; + +pub struct Sphere { + center: Point3, + radius: f64, +} + +impl Sphere { + pub fn new(center: Point3, radius: f64) -> Self { + Self { center, radius } + } +} + +impl Intersect for Sphere { + fn intersect(&self, ray: &Ray) -> Option { + let a = ray.dir.magnitude_squared(); + let b = ray.dir.dot(&(self.center - ray.orig)); + let c = (self.center - ray.orig).magnitude_squared() - self.radius * self.radius; + let discriminant = b * b - a * c; + if discriminant < 0.0 { + return None; + } + Some((b - discriminant.sqrt()) / a) + } +}