Multisphärisch

This commit is contained in:
Jonathan Flueren 2022-05-04 18:21:48 +02:00
parent 1c1fca3dfc
commit 94848e45ac
4 changed files with 94 additions and 18 deletions

View file

@ -4,8 +4,9 @@ use super::Vec3;
pub struct HitRecord { pub struct HitRecord {
p: Point3, p: Point3,
normal: Vec3, pub normal: Vec3,
t: f64, pub t: f64,
front_face: bool,
} }
pub struct Sphere { pub struct Sphere {
@ -14,11 +15,35 @@ pub struct Sphere {
} }
pub trait Hittable { 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 { impl Sphere {
fn new(cen: Point3, r: f64) -> Self { pub fn new(cen: Point3, r: f64) -> Self {
Sphere { Sphere {
center: cen, center: cen,
radius: r, radius: r,
@ -27,22 +52,22 @@ impl Sphere {
} }
impl Hittable for 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 oc = r.origin() - self.center;
let a = r.direction().length_squared(); // gleiches Ergebnis wie Skalarprodukt 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 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 { if discriminant < 0.0 {
return false; return false;
} }
let sqrtd = discriminant.sqrt(); let sqrtd = discriminant.sqrt();
let root = (-b / 2.0 - sqrtd) / a; let root = (-half_b - sqrtd) / a;
if root < t_min || t_max < root { 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 { if root2 < t_min || t_max < root {
return false; return false;
} }
@ -50,7 +75,8 @@ impl Hittable for Sphere {
rec.t = root; rec.t = root;
rec.p = r.at(rec.t); 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; return true;
} }

40
src/hittable_list.rs Normal file
View file

@ -0,0 +1,40 @@
use super::Hittable;
use super::Ray;
use super::HitRecord;
pub struct HittableList {
objects: Vec<Box<dyn Hittable>>,
}
impl HittableList {
pub fn new()-> Self {
HittableList {
objects: Vec::<Box<dyn Hittable>>::new()
}
}
pub fn clear(&mut self) {
self.objects.clear();
}
pub fn add(&mut self, obj: Box<dyn Hittable>) {
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;
}
}

View file

@ -1,7 +1,9 @@
mod color; mod color;
mod hittable; mod hittable;
mod hittable_list;
mod ray; mod ray;
mod vec3; mod vec3;
mod utility;
use ray::Ray; use ray::Ray;
use std::env; use std::env;
use std::fs::File; use std::fs::File;
@ -10,6 +12,10 @@ use std::io::Write;
use vec3::Color; use vec3::Color;
use vec3::Point3; use vec3::Point3;
use vec3::Vec3; 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 { fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 {
let oc = r.origin() - *center; 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 { fn ray_color(r: &Ray, world: &HittableList) -> Color {
let t = hit_sphere(&Point3::new(0.0, 0.0, -1.0), 0.5, r); let mut rec = HitRecord::empty();
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);
}
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 unit_direction = r.direction();
let t = 0.5 * (unit_direction.y() + 1.0); 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); 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 // Image
let aspect_ratio = 16.0 / 9.0; 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; let image_height = (image_width as f64 / aspect_ratio) as u64;
// World
let mut world = HittableList::new();
world.add(Box::<Sphere>::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));
world.add(Box::<Sphere>::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
// Camera // Camera
let viewport_height = 2.0; let viewport_height = 2.0;
let viewport_width = aspect_ratio * viewport_height; let viewport_width = aspect_ratio * viewport_height;
@ -74,7 +84,7 @@ fn main() {
origin, origin,
lower_left_corner + u * horizontal + v * vertical - 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); color::write_color(&mut file, pixel_color);
} }

0
src/utility.rs Normal file
View file