From 745fafeaad4ab0a8ced10901dc9b548416f7c676 Mon Sep 17 00:00:00 2001 From: Jonathan Flueren Date: Wed, 29 Jun 2022 16:17:28 +0200 Subject: [PATCH] More spheres, formatting --- src/camera.rs | 20 ++++---- src/hittable.rs | 10 +--- src/main.rs | 126 ++++++++++++++++++++++-------------------------- src/material.rs | 89 ++++++++++++++++++++++------------ src/utility.rs | 2 +- src/vec3.rs | 10 ++-- 6 files changed, 133 insertions(+), 124 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 1661a58..b05cc4b 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -9,22 +9,21 @@ pub struct Camera { v: Vec3, w: Vec3, lens_radius: f64, - } impl Camera { pub fn new( - lookfrom: Point3, - lookat: Point3, - vup: Vec3, + lookfrom: Point3, + lookat: Point3, + vup: Vec3, vfov: f64, // vertical field of view in degrees aspect_ratio: f64, - aperture: f64, + aperture: f64, focus_dist: f64, ) -> Self { let theta = vfov.to_radians(); - let h = (theta/2.0).tan(); - let viewport_height = 2.0*h; + let h = (theta / 2.0).tan(); + let viewport_height = 2.0 * h; let viewport_width = aspect_ratio * viewport_height; let w = Vec3::unit_vector(lookfrom - lookat); @@ -34,9 +33,9 @@ impl Camera { let origin = lookfrom; let horizontal = focus_dist * viewport_width * u; let vertical = focus_dist * viewport_height * v; - let lower_left_corner = origin - horizontal/2.0 - vertical/2.0 - focus_dist*w; + let lower_left_corner = origin - horizontal / 2.0 - vertical / 2.0 - focus_dist * w; - let lens_radius = aperture / 2.0; + let lens_radius = aperture / 2.0; return Camera { origin, @@ -51,13 +50,12 @@ impl Camera { } pub fn get_ray(&self, u: f64, v: f64) -> Ray { - let rd = self.lens_radius * Vec3::random_in_unit_disk(); let offset = rd.x() * self.u + rd.y() * self.v; return Ray::new( self.origin + offset, self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin - offset, - ) + ); } } diff --git a/src/hittable.rs b/src/hittable.rs index 56f3a91..59913e0 100644 --- a/src/hittable.rs +++ b/src/hittable.rs @@ -1,12 +1,4 @@ -use super::{ - Point3, - Vec3, - Color, - Ray, - Material, - Arc, - Metal -}; +use super::{Arc, Color, Material, Metal, Point3, Ray, Vec3}; pub struct HitRecord { pub p: Point3, diff --git a/src/main.rs b/src/main.rs index 328e9e0..3a304b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,22 +4,22 @@ mod camera; mod color; mod hittable; mod hittable_list; +mod material; mod ray; mod utility; mod vec3; -mod material; use camera::Camera; use hittable::{HitRecord, Hittable, Sphere}; use hittable_list::HittableList; use image::{Rgb, RgbImage}; +use material::{Dielectric, Lambertian, Material, Metal}; use ray::Ray; use rayon::prelude::*; use std::env; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; use vec3::{Color, Point3, Vec3}; -use material::{Material, Lambertian, Metal, Dielectric}; fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color { let mut rec = HitRecord::empty(); @@ -31,11 +31,14 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color { if world.hit(r, 0.001, f64::INFINITY, &mut rec) { let mut scattered = Ray::new(Point3::null(), Vec3::null()); let mut attenuation = Color::null(); - if rec.mat_ptr.scatter(r, &rec, &mut attenuation, &mut scattered) { - return attenuation * ray_color(&scattered, world, depth-1); + if rec + .mat_ptr + .scatter(r, &rec, &mut attenuation, &mut scattered) + { + return attenuation * ray_color(&scattered, world, depth - 1); } return Color::null(); - + //let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere(); //return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1); } @@ -47,62 +50,63 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color { fn random_world() -> HittableList { let mut world = HittableList::new(); - let material_ground = Arc::new(Lambertian::new(&Color::new(0.1, 0.1, 0.1))); - - //let material_center = Arc::new(Lambertian::new(&Color::new(0.7, 0.1, 0.2))); - //let material_center = Arc::new(Dielectric::new(1.5)); - //let material_blue = Arc::new(Lambertian::new(&Color::new(0.2, 0.1, 0.7))); - //let material_metal = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.1)); - //let material_metal_fuzz = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 1.0)); - //let material_mirror = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8), 0.0)); - //let material_dielectric = Arc::new(Dielectric::new(1.5)); - //let material_light = Arc::new(Lambertian::new(&Color::new(2.0, 1.0, 0.0))); - - - + let material_ground = Arc::new(Lambertian::new(&Color::new(0.01, 0.01, 0.01))); world.add(Box::::new(Sphere::new( - Point3::new(0.0, -1000.0, 0.0), - 1000.0, + Point3::new(0.0, -50000.0, 0.0), + 50000.0, material_ground.clone(), ))); (-6..5).into_iter().for_each(|a| { (-6..5).into_iter().for_each(|b| { let choose_mat = utility::random_f64(); - let center = Point3::new(a as f64 + 0.9 * utility::random_f64(), 0.2, b as f64 + 0.9 * utility::random_f64()); + let center = Point3::new( + 1.5 * a as f64 + 1.3 * utility::random_f64(), + 0.2, + 1.5 * b as f64 + 1.3 * utility::random_f64(), + ); if (center - Point3::new(4.0, 0.2, 0.0)).length() > 0.9 { - if choose_mat < 0.8 { // diffuse - let sphere_material = Arc::new(Lambertian::new(&(Color::random_f64() * Color::random_f64()))); + if choose_mat < 0.8 { + // diffuse + let sphere_material = Arc::new(Lambertian::new( + &(Color::random_f64() * Color::random_f64()), + )); world.add(Box::::new(Sphere::new( center, 0.2, - sphere_material.clone() + sphere_material.clone(), ))); - } else if choose_mat < 0.95 { // metal - let sphere_material = Arc::new(Metal::new(&Color::random_rng(0.5, 1.0), utility::random_rng(0.0, 0.5))); + } else if choose_mat < 0.95 { + // metal + let sphere_material = Arc::new(Metal::new( + &Color::random_rng(0.5, 1.0), + utility::random_rng(0.0, 0.5), + )); world.add(Box::::new(Sphere::new( center, 0.2, - sphere_material.clone() + sphere_material.clone(), ))); - } else { // glass + } else { + // glass let sphere_material = Arc::new(Dielectric::new(1.5)); world.add(Box::::new(Sphere::new( center, 0.2, - sphere_material.clone() + sphere_material.clone(), ))); } - } }); }); let material1 = Arc::new(Dielectric::new(1.5)); - let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0)); let material2 = Arc::new(Lambertian::new(&Color::new(0.4, 0.2, 0.1))); - + let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0)); + let material4 = Arc::new(Dielectric::new(2.0)); + let material5 = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 0.0)); + world.add(Box::::new(Sphere::new( Point3::new(0.0, 1.0, 0.0), 1.0, @@ -121,41 +125,17 @@ fn random_world() -> HittableList { material3.clone(), ))); - /* world.add(Box::::new(Sphere::new( - Point3::new(-2.0*r, 0.1, -2.0), - r, - material_dielectric.clone(), + Point3::new(-2.0, 2.0, -5.0), + 2.0, + material4.clone(), ))); - world.add(Box::::new(Sphere::new( - Point3::new(r, 0.0, -1.0), - r, - material_dielectric.clone(), - ))); - world.add(Box::::new(Sphere::new( - Point3::new(-1.5, 1.3, -1.7), - 0.4, - material_mirror.clone(), - ))); - world.add(Box::::new(Sphere::new( - Point3::new(-0.5, 0.5, 1.0), - 0.4, - material_blue.clone(), - ))); - world.add(Box::::new(Sphere::new( - Point3::new(0.5, 1.0, 0.3), - 0.3, - material_light.clone(), - ))); - */ - /* - for i in -15..15 { - for j in -15..15 { - world.add(Box::::new(Sphere::new(Point3::new(j as f64/5.0 as f64, i as f64/5.0 as f64, -1.5), 0.08))); - } - } - */ + world.add(Box::::new(Sphere::new( + Point3::new(-3.6, 2.0, -2.0), + 0.6, + material5.clone(), + ))); return world; } @@ -166,23 +146,31 @@ fn main() { // Image let aspect_ratio = 16.0 / 9.0; - let image_width = 1920; + let image_width = 1000; let image_height = (image_width as f64 / aspect_ratio) as u32; let samples_per_pixel = 100_u32; let max_depth = 50; - let vfov = 20.0; - let lookfrom = Point3::new(10.0, 10.0, 13.0); + let vfov = 25.0; + let lookfrom = Point3::new(10.0, 4.0, 13.0); let lookat = Point3::new(0.0, 0.0, 0.0); let vup = Vec3::new(0.0, 1.0, 0.0); - let dist_to_focus = 15.0; + let dist_to_focus = 17.0; let aperture = 0.1; // World let world = random_world(); // Camera - let cam = Camera::new(lookfrom, lookat, vup, vfov, aspect_ratio, aperture, dist_to_focus); + let cam = Camera::new( + lookfrom, + lookat, + vup, + vfov, + aspect_ratio, + aperture, + dist_to_focus, + ); // Render let args: Vec = env::args().collect(); diff --git a/src/material.rs b/src/material.rs index 690dbf1..84b70f5 100644 --- a/src/material.rs +++ b/src/material.rs @@ -1,10 +1,4 @@ -use super::{ - Ray, - HitRecord, - Color, - Vec3, - utility, -}; +use super::{utility, Color, HitRecord, Ray, Vec3}; pub struct Lambertian { albedo: Color, @@ -23,27 +17,36 @@ pub struct Dielectric { ir: f64, } - pub trait Material: Sync + Send { - fn scatter(&self,r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool; + fn scatter( + &self, + r_in: &Ray, + rec: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool; } impl Lambertian { pub fn new(a: &Color) -> Self { - Lambertian { - albedo: a.clone(), - } + Lambertian { albedo: a.clone() } } } impl Material for Lambertian { - fn scatter(&self, _r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + _r_in: &Ray, + rec: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { let mut scatter_direction = rec.normal + Vec3::random_unit_vector(); - + if scatter_direction.near_zero() { scatter_direction = rec.normal; } - + *scattered = Ray::new(rec.p, scatter_direction); *attenuation = self.albedo.clone(); return true; @@ -60,10 +63,16 @@ impl Metal { } impl Material for Metal { - fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + r_in: &Ray, + rec: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal); - *scattered = Ray::new(rec.p, reflected + self.fuzz*Vec3::random_in_unit_sphere()); + *scattered = Ray::new(rec.p, reflected + self.fuzz * Vec3::random_in_unit_sphere()); *attenuation = self.albedo.clone(); return Vec3::dot(scattered.direction(), rec.normal) > 0.0; @@ -72,22 +81,27 @@ impl Material for Metal { impl Mirror { pub fn new(a: &Color) -> Self { - Mirror { - albedo: *a, - } + Mirror { albedo: *a } } } impl Material for Mirror { - fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { - if utility::random_f64() > 0.8 { // Reflektiert + fn scatter( + &self, + r_in: &Ray, + rec: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { + if utility::random_f64() > 0.8 { + // Reflektiert let reflected = Vec3::reflect(&Vec3::unit_vector(r_in.direction()), &rec.normal); *scattered = Ray::new(rec.p, reflected); *attenuation = self.albedo.clone(); return Vec3::dot(scattered.direction(), rec.normal) > 0.0; - - } else { // Geht geradeaus durch + } else { + // Geht geradeaus durch let reflected = r_in.direction().clone(); *scattered = Ray::new(rec.p, reflected); @@ -106,27 +120,40 @@ impl Dielectric { } fn reflectance(cosine: f64, ref_idx: f64) -> f64 { - let r0 = ((1.0-ref_idx) / (1.0+ref_idx)).powi(2); - return r0 + (1.0-r0)*(1.0 - cosine).powi(5); + let r0 = ((1.0 - ref_idx) / (1.0 + ref_idx)).powi(2); + return r0 + (1.0 - r0) * (1.0 - cosine).powi(5); } } impl Material for Dielectric { - fn scatter(&self, r_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { + fn scatter( + &self, + r_in: &Ray, + rec: &HitRecord, + attenuation: &mut Color, + scattered: &mut Ray, + ) -> bool { *attenuation = Color::new(1.0, 1.0, 1.0); - let refraction_ratio = if rec.front_face { 1.0 / self.ir } else { self.ir }; + let refraction_ratio = if rec.front_face { + 1.0 / self.ir + } else { + self.ir + }; let unit_direction = Vec3::unit_vector(r_in.direction()); let cos_theta = Vec3::dot(-1.0 * unit_direction, rec.normal).min(1.0); - let sin_theta = (1.0 - cos_theta*cos_theta).sqrt(); + let sin_theta = (1.0 - cos_theta * cos_theta).sqrt(); let mut direction = Vec3::refract(&unit_direction, &rec.normal, refraction_ratio); // can reflect - if refraction_ratio * sin_theta > 1.0 || Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64() { // must reflect + if refraction_ratio * sin_theta > 1.0 + || Dielectric::reflectance(cos_theta, refraction_ratio) > utility::random_f64() + { + // must reflect direction = Vec3::reflect(&unit_direction, &rec.normal); } *scattered = Ray::new(rec.p, direction); return true; } -} \ No newline at end of file +} diff --git a/src/utility.rs b/src/utility.rs index 4532c9f..ff0f6ee 100644 --- a/src/utility.rs +++ b/src/utility.rs @@ -22,4 +22,4 @@ pub fn clamp(x: f64, min: f64, max: f64) -> f64 { return max; } return x; -} \ No newline at end of file +} diff --git a/src/vec3.rs b/src/vec3.rs index aec711c..22b3a7d 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -47,7 +47,7 @@ impl Vec3 { } pub fn reflect(v: &Self, n: &Self) -> Self { - *v - 2.0*Self::dot(*v, *n) * *(n) + *v - 2.0 * Self::dot(*v, *n) * *(n) } pub fn refract(uv: &Self, n: &Self, etai_over_etat: f64) -> Self { @@ -90,7 +90,11 @@ impl Vec3 { pub fn random_in_unit_disk() -> Self { loop { - let p = Vec3::new(utility::random_rng(-1.0, 1.0), utility::random_rng(-1.0, 1.0), 0.0); + let p = Vec3::new( + utility::random_rng(-1.0, 1.0), + utility::random_rng(-1.0, 1.0), + 0.0, + ); if p.length_squared() >= 1.0 { continue; } @@ -166,7 +170,7 @@ impl Mul for Vec3 { type Output = Self; fn mul(self, rhs: Self) -> Self { - Self::new(self.x()*rhs.x(), self.y()*rhs.y(), self.z()*rhs.z()) + Self::new(self.x() * rhs.x(), self.y() * rhs.y(), self.z() * rhs.z()) } }