From 24d3f102e32bea0324d08b2f6a3e41fead5579cf Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 10 Oct 2020 02:00:05 +0100 Subject: Add moving spheres --- src/main.rs | 24 +++++++++++++++++---- src/material.rs | 21 +++++++++++++------ src/sphere.rs | 65 +++++++++++++-------------------------------------------- 3 files changed, 50 insertions(+), 60 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3db5b97..b014e4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,8 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { scene.add(Box::new(sphere::Sphere::new( vec3(0.0, -1000.0, 0.0), + 0.0, + 1.0, 1000.0, Box::new(material::Lambertian::new(vec3(0.5, 0.5, 0.5))), ))); @@ -34,8 +36,12 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { // diffuse let albedo = utils::random_vector3(rng, 0.0, 1.0) .mul_element_wise(utils::random_vector3(rng, 0.0, 1.0)); - scene.add(Box::new(sphere::Sphere::new( + let moving_center = center + vec3(0.0, rng.gen_range(0.0, 0.5), 0.0); + scene.add(Box::new(sphere::Sphere::new_moving( center, + moving_center, + 0.0, + 1.0, 0.2, Box::new(material::Lambertian::new(albedo)), ))); @@ -45,6 +51,8 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { let fuzz = rng.gen_range(0.0, 0.5); scene.add(Box::new(sphere::Sphere::new( center, + 0.0, + 1.0, 0.2, Box::new(material::Metal::new(albedo, fuzz)), ))); @@ -52,6 +60,8 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { // glass scene.add(Box::new(sphere::Sphere::new( center, + 0.0, + 1.0, 0.2, Box::new(material::Dielectric::new(1.5)), ))); @@ -62,18 +72,24 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { scene.add(Box::new(sphere::Sphere::new( vec3(0.0, 1.0, 0.0), + 0.0, + 1.0, 1.0, Box::new(material::Dielectric::new(1.5)), ))); scene.add(Box::new(sphere::Sphere::new( vec3(-4.0, 1.0, 0.0), + 0.0, + 1.0, 1.0, Box::new(material::Lambertian::new(vec3(0.4, 0.2, 0.1))), ))); scene.add(Box::new(sphere::Sphere::new( vec3(4.0, 1.0, 0.0), + 0.0, + 1.0, 1.0, Box::new(material::Metal::new(vec3(0.7, 0.6, 0.5), 0.0)), ))); @@ -82,9 +98,9 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene { } fn main() { - let image_width = 400; - let image_height = 200; - let samples = 400; + let image_width = 800; + let image_height = 400; + let samples = 1000; let threads = 4; let max_depth = 50; let aspect_ratio = image_width as f64 / image_height as f64; diff --git a/src/material.rs b/src/material.rs index 91e7c02..9644c2b 100644 --- a/src/material.rs +++ b/src/material.rs @@ -20,11 +20,11 @@ impl Lambertian { } impl Material for Lambertian { - fn scatter(&self, rng: &mut ThreadRng, _ray: &Ray, hit: &Hit) -> Option { + fn scatter(&self, rng: &mut ThreadRng, ray: &Ray, hit: &Hit) -> Option { let scatter_direction = hit.normal + random_unit_vector(rng); Some(NextRay::new( self.albedo, - Ray::new(hit.p, scatter_direction, 0.0), + Ray::new(hit.p, scatter_direction, ray.time), )) } } @@ -47,7 +47,7 @@ impl Material for Metal { let scattered = Ray::new( hit.p, reflected + self.fuzz * random_in_unit_sphere(rng), - 0.0, + ray.time, ); if dot(scattered.dir, hit.normal) > 0.0 { Some(NextRay::new(self.albedo, scattered)) @@ -82,16 +82,25 @@ impl Material for Dielectric { if etai_over_etat * sin_theta > 1.0 { let reflected = reflect(&unit_direction, &hit.normal); - return Some(NextRay::new(attenuation, Ray::new(hit.p, reflected, 0.0))); + return Some(NextRay::new( + attenuation, + Ray::new(hit.p, reflected, ray.time), + )); } let reflect_prob = schlick(cos_theta, etai_over_etat); if rng.gen::() < reflect_prob { let reflected = reflect(&unit_direction, &hit.normal); - return Some(NextRay::new(attenuation, Ray::new(hit.p, reflected, 0.0))); + return Some(NextRay::new( + attenuation, + Ray::new(hit.p, reflected, ray.time), + )); } let refracted = refract(&unit_direction, &hit.normal, etai_over_etat); - Some(NextRay::new(attenuation, Ray::new(hit.p, refracted, 0.0))) + Some(NextRay::new( + attenuation, + Ray::new(hit.p, refracted, ray.time), + )) } } diff --git a/src/sphere.rs b/src/sphere.rs index 59ca498..573f891 100644 --- a/src/sphere.rs +++ b/src/sphere.rs @@ -6,7 +6,10 @@ use cgmath::{dot, Vector3}; use core::borrow::Borrow; pub struct Sphere { - center: Vector3, + center0: Vector3, + center1: Vector3, + time0: f64, + time1: f64, radius: f64, material: Box, } @@ -14,68 +17,30 @@ pub struct Sphere { impl Sphere { pub fn new( center: Vector3, + time0: f64, + time1: f64, radius: f64, material: Box, ) -> Sphere { Sphere { - center, + center0: center, + center1: center, + time0, + time1, radius, material, } } -} - -impl Hittable for Sphere { - fn is_hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { - let oc = ray.orig - self.center; - let a = ray.dir.magnitude2(); - let b = dot(oc, ray.dir); - let c = oc.magnitude2() - self.radius * self.radius; - let discriminant = b * b - a * c; - - if discriminant > 0.0 { - let soln = (-b - discriminant.sqrt()) / a; - if soln < t_max && soln > t_min { - return Some(Hit::new( - ray, - soln, - (ray.at(soln) - self.center) / self.radius, - self.material.borrow(), - )); - } - let soln = (-b + discriminant.sqrt()) / a; - if soln < t_max && soln > t_min { - return Some(Hit::new( - ray, - soln, - (ray.at(soln) - self.center) / self.radius, - self.material.borrow(), - )); - } - } - None - } -} -struct MovingSphere { - center0: Vector3, - center1: Vector3, - time0: f64, - time1: f64, - radius: f64, - material: Box, -} - -impl MovingSphere { - pub fn new( + pub fn new_moving( center0: Vector3, center1: Vector3, time0: f64, time1: f64, radius: f64, material: Box, - ) -> MovingSphere { - MovingSphere { + ) -> Sphere { + Sphere { center0, center1, time0, @@ -87,11 +52,11 @@ impl MovingSphere { pub fn center(&self, time: f64) -> Vector3 { self.center0 - + ((time + self.time0) / (self.time0 + self.time1)) * (self.center1 - self.center0) + + ((time - self.time0) / (self.time1 - self.time0)) * (self.center1 - self.center0) } } -impl Hittable for MovingSphere { +impl Hittable for Sphere { fn is_hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { let oc = ray.orig - self.center(ray.time); let a = ray.dir.magnitude2(); -- cgit