aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Herklotz <git@yannherklotz.com>2020-10-10 02:00:05 +0100
committerYann Herklotz <git@yannherklotz.com>2020-10-10 02:00:05 +0100
commit24d3f102e32bea0324d08b2f6a3e41fead5579cf (patch)
tree84b29b6d786a464e040c43866c0a68f81d937900
parent495d1c9c113098f24767b595c7e830f0fa8bc991 (diff)
downloadleela-24d3f102e32bea0324d08b2f6a3e41fead5579cf.tar.gz
leela-24d3f102e32bea0324d08b2f6a3e41fead5579cf.zip
Add moving spheres
-rw-r--r--src/main.rs24
-rw-r--r--src/material.rs21
-rw-r--r--src/sphere.rs65
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<NextRay> {
+ fn scatter(&self, rng: &mut ThreadRng, ray: &Ray, hit: &Hit) -> Option<NextRay> {
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::<f64>() < 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<f64>,
+ center0: Vector3<f64>,
+ center1: Vector3<f64>,
+ time0: f64,
+ time1: f64,
radius: f64,
material: Box<dyn Material + std::marker::Sync>,
}
@@ -14,68 +17,30 @@ pub struct Sphere {
impl Sphere {
pub fn new(
center: Vector3<f64>,
+ time0: f64,
+ time1: f64,
radius: f64,
material: Box<dyn Material + std::marker::Sync>,
) -> 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<Hit> {
- 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<f64>,
- center1: Vector3<f64>,
- time0: f64,
- time1: f64,
- radius: f64,
- material: Box<dyn Material + std::marker::Sync>,
-}
-
-impl MovingSphere {
- pub fn new(
+ pub fn new_moving(
center0: Vector3<f64>,
center1: Vector3<f64>,
time0: f64,
time1: f64,
radius: f64,
material: Box<dyn Material + std::marker::Sync>,
- ) -> MovingSphere {
- MovingSphere {
+ ) -> Sphere {
+ Sphere {
center0,
center1,
time0,
@@ -87,11 +52,11 @@ impl MovingSphere {
pub fn center(&self, time: f64) -> Vector3<f64> {
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<Hit> {
let oc = ray.orig - self.center(ray.time);
let a = ray.dir.magnitude2();