diff --git a/src/hittable.rs b/src/hittable.rs index 0b9097a..877b294 100644 --- a/src/hittable.rs +++ b/src/hittable.rs @@ -4,8 +4,9 @@ use super::Vec3; pub struct HitRecord { p: Point3, - normal: Vec3, - t: f64, + pub normal: Vec3, + pub t: f64, + front_face: bool, } pub struct Sphere { @@ -14,11 +15,35 @@ pub struct Sphere { } pub trait Hittable { - fn hit(&self, r: Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool; + fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool; +} + +impl HitRecord { + fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) { + self.front_face = Vec3::dot(r.direction(), outward_normal) < 0.0; + if self.front_face { + self.normal = outward_normal; + } else { + self.normal = (-1.0)*outward_normal; + } + } + + pub fn new(p: Point3, normal: Vec3, t: f64, front_face: bool) -> Self { + HitRecord { + p: p, + normal: normal, + t: t, + front_face: front_face, + } + } + + pub fn empty() -> Self { + Self::new(Point3::new(0.0,0.0,0.0), Vec3::new(0.0,0.0,0.0), 0.0, false) + } } impl Sphere { - fn new(cen: Point3, r: f64) -> Self { + pub fn new(cen: Point3, r: f64) -> Self { Sphere { center: cen, radius: r, @@ -27,22 +52,22 @@ impl Sphere { } impl Hittable for Sphere { - fn hit(&self, r: Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool { + fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool { let oc = r.origin() - self.center; let a = r.direction().length_squared(); // gleiches Ergebnis wie Skalarprodukt - let b = 2.0 * Vec3::dot(oc, r.direction()); + let half_b = Vec3::dot(oc, r.direction()); let c = oc.length_squared() - self.radius * self.radius; - let discriminant = b * b - 4.0 * a * c; + let discriminant = half_b * half_b - a * c; if discriminant < 0.0 { return false; } let sqrtd = discriminant.sqrt(); - let root = (-b / 2.0 - sqrtd) / a; + let root = (-half_b - sqrtd) / a; if root < t_min || t_max < root { - let root2 = (-b / 2.0 + sqrtd) / a; + let root2 = (-half_b + sqrtd) / a; if root2 < t_min || t_max < root { return false; } @@ -50,7 +75,8 @@ impl Hittable for Sphere { rec.t = root; rec.p = r.at(rec.t); - rec.normal = (rec.p - self.center) / self.radius; + let outward_normal = (rec.p - self.center) / self.radius; + rec.set_face_normal(r, outward_normal); return true; } diff --git a/src/hittable_list.rs b/src/hittable_list.rs new file mode 100644 index 0000000..05da354 --- /dev/null +++ b/src/hittable_list.rs @@ -0,0 +1,40 @@ +use super::Hittable; +use super::Ray; +use super::HitRecord; + +pub struct HittableList { + objects: Vec>, +} + +impl HittableList { + pub fn new()-> Self { + HittableList { + objects: Vec::>::new() + } + } + + pub fn clear(&mut self) { + self.objects.clear(); + } + + pub fn add(&mut self, obj: Box) { + self.objects.push(obj); + } + + pub fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool { + + let mut hit_anything = false; + let mut closest_so_far = t_max; + + for obj in &self.objects { + let mut temp_rec = HitRecord::empty(); + if obj.hit(&r, t_min, closest_so_far, &mut temp_rec) { + hit_anything = true; + closest_so_far = temp_rec.t; + *rec = temp_rec; + } + } + + return hit_anything; + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index ec4cf24..54f36e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ mod color; mod hittable; +mod hittable_list; mod ray; mod vec3; +mod utility; use ray::Ray; use std::env; use std::fs::File; @@ -10,6 +12,10 @@ use std::io::Write; use vec3::Color; use vec3::Point3; use vec3::Vec3; +use hittable::Hittable; +use hittable::Sphere; +use hittable_list::HittableList; +use hittable::HitRecord; fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 { let oc = r.origin() - *center; @@ -25,13 +31,12 @@ fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 { } } -fn ray_color(r: &Ray) -> Color { - let t = hit_sphere(&Point3::new(0.0, 0.0, -1.0), 0.5, r); - if t > 0.0 { - let n = Vec3::unit_vector(r.at(t) - Vec3::new(0.0, 0.0, -1.0)); - return 0.5 * Color::new(n.x() + 1.0, n.y() + 1.0, n.z() + 1.0); - } +fn ray_color(r: &Ray, world: &HittableList) -> Color { + let mut rec = HitRecord::empty(); + if world.hit(r, 0.0, f64::INFINITY, &mut rec) { + return 0.5 * (rec.normal + Color::new(1.0, 1.0, 1.0)); + } let unit_direction = r.direction(); let t = 0.5 * (unit_direction.y() + 1.0); return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0); @@ -43,9 +48,14 @@ fn main() { // Image let aspect_ratio = 16.0 / 9.0; - let image_width = 2000; + let image_width = 1000; let image_height = (image_width as f64 / aspect_ratio) as u64; + // World + let mut world = HittableList::new(); + world.add(Box::::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5))); + world.add(Box::::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0))); + // Camera let viewport_height = 2.0; let viewport_width = aspect_ratio * viewport_height; @@ -74,7 +84,7 @@ fn main() { origin, lower_left_corner + u * horizontal + v * vertical - origin, ); - let pixel_color = ray_color(&r); + let pixel_color = ray_color(&r, &mut world); color::write_color(&mut file, pixel_color); } diff --git a/src/utility.rs b/src/utility.rs new file mode 100644 index 0000000..e69de29