aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYann Herklotz <git@yannherklotz.com>2020-10-10 00:12:12 +0100
committerYann Herklotz <git@yannherklotz.com>2020-10-10 00:12:12 +0100
commit495d1c9c113098f24767b595c7e830f0fa8bc991 (patch)
tree95eac21eacecadc58f23a59216e764ddd6928979 /src
parentdd5ac7c5fe336e9cac794cfa72d139613a99b466 (diff)
downloadleela-495d1c9c113098f24767b595c7e830f0fa8bc991.tar.gz
leela-495d1c9c113098f24767b595c7e830f0fa8bc991.zip
Format all the files and add moving sphere
Diffstat (limited to 'src')
-rw-r--r--src/camera.rs42
-rw-r--r--src/colour.rs0
-rw-r--r--src/hittable.rs20
-rw-r--r--src/main.rs88
-rw-r--r--src/material.rs39
-rw-r--r--src/ray.rs9
-rw-r--r--src/render.rs72
-rw-r--r--src/scene.rs8
-rw-r--r--src/sphere.rs104
-rw-r--r--src/utils.rs51
10 files changed, 320 insertions, 113 deletions
diff --git a/src/camera.rs b/src/camera.rs
index 7564c12..01cb977 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -1,8 +1,8 @@
-use cgmath::prelude::*;
-use cgmath::{Vector3, vec3};
-use rand::prelude::*;
use crate::ray::Ray;
use crate::utils::random_in_unit_disk;
+use cgmath::prelude::*;
+use cgmath::{vec3, Vector3};
+use rand::prelude::*;
pub struct Camera {
origin: Vector3<f64>,
@@ -12,12 +12,23 @@ pub struct Camera {
u: Vector3<f64>,
v: Vector3<f64>,
w: Vector3<f64>,
- lens_radius: f64
+ lens_radius: f64,
+ time0: f64,
+ time1: f64,
}
impl Camera {
- pub fn new(lookfrom: &Vector3<f64>, lookat: &Vector3<f64>, vup: &Vector3<f64>,
- vfov: f64, aspect: f64, aperture: f64, focus_dist: f64) -> Camera {
+ pub fn new(
+ lookfrom: &Vector3<f64>,
+ lookat: &Vector3<f64>,
+ vup: &Vector3<f64>,
+ vfov: f64,
+ aspect: f64,
+ aperture: f64,
+ focus_dist: f64,
+ time0: f64,
+ time1: f64,
+ ) -> Camera {
let lens_radius = aperture / 2.0;
let half_height = (vfov / 2.0).tan();
let half_width = aspect * half_height;
@@ -26,19 +37,28 @@ impl Camera {
let v = w.cross(u);
Camera {
origin: *lookfrom,
- lower_left_corner: lookfrom - half_width * focus_dist * u
- - half_height * focus_dist * v - focus_dist * w,
+ lower_left_corner: lookfrom
+ - half_width * focus_dist * u
+ - half_height * focus_dist * v
+ - focus_dist * w,
horizontal: 2.0 * half_width * focus_dist * u,
vertical: 2.0 * half_height * focus_dist * v,
lens_radius,
- u, v, w
+ u,
+ v,
+ w,
+ time0,
+ time1,
}
}
pub fn get_ray(&self, rng: &mut ThreadRng, s: f64, t: f64) -> Ray {
let rd = self.lens_radius * random_in_unit_disk(rng);
let offset = self.u * rd.x + self.v * rd.y;
- Ray::new(self.origin + offset,
- self.lower_left_corner + s * self.horizontal + t * self.vertical - self.origin - offset)
+ Ray::new(
+ self.origin + offset,
+ self.lower_left_corner + s * self.horizontal + t * self.vertical - self.origin - offset,
+ rng.gen_range(self.time0, self.time1),
+ )
}
}
diff --git a/src/colour.rs b/src/colour.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/colour.rs
diff --git a/src/hittable.rs b/src/hittable.rs
index dcc5006..b5a4f20 100644
--- a/src/hittable.rs
+++ b/src/hittable.rs
@@ -1,22 +1,32 @@
-use cgmath::{Vector3, dot};
use crate::material::Material;
use crate::ray::Ray;
+use cgmath::{dot, Vector3};
pub struct Hit<'a> {
pub t: f64,
pub p: Vector3<f64>,
pub normal: Vector3<f64>,
pub front_face: bool,
- pub material: &'a (dyn Material + std::marker::Sync)
+ pub material: &'a (dyn Material + std::marker::Sync),
}
impl<'a> Hit<'a> {
- pub fn new(ray: &Ray, t: f64, out_normal: Vector3<f64>, material: &'a(dyn Material + std::marker::Sync))
- -> Hit<'a> {
+ pub fn new(
+ ray: &Ray,
+ t: f64,
+ out_normal: Vector3<f64>,
+ material: &'a (dyn Material + std::marker::Sync),
+ ) -> Hit<'a> {
let front_face = dot(ray.dir, out_normal) < 0.0;
let normal = if front_face { out_normal } else { -out_normal };
let p = ray.at(t);
- Hit { t, p, normal, front_face, material }
+ Hit {
+ t,
+ p,
+ normal,
+ front_face,
+ material,
+ }
}
}
diff --git a/src/main.rs b/src/main.rs
index f1a627f..3db5b97 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,5 @@
use cgmath::prelude::*;
-use cgmath::{Vector3, vec3};
+use cgmath::{vec3, Vector3};
use rand::prelude::*;
use std::f64::consts::PI;
@@ -16,44 +16,67 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene {
let mut scene = scene::Scene::new();
scene.add(Box::new(sphere::Sphere::new(
- vec3(0.0, -1000.0, 0.0), 1000.0, Box::new(material::Lambertian::new(vec3(0.5, 0.5, 0.5))))));
+ vec3(0.0, -1000.0, 0.0),
+ 1000.0,
+ Box::new(material::Lambertian::new(vec3(0.5, 0.5, 0.5))),
+ )));
- for a in -11 .. 11 {
- for b in -11 .. 11 {
+ for a in -11..11 {
+ for b in -11..11 {
let choose_mat: f64 = rng.gen();
- let center = vec3(a as f64 + 0.9*rng.gen::<f64>(), 0.2, b as f64 + 0.9*rng.gen::<f64>());
+ let center = vec3(
+ a as f64 + 0.9 * rng.gen::<f64>(),
+ 0.2,
+ b as f64 + 0.9 * rng.gen::<f64>(),
+ );
if (center - vec3(4.0, 0.2, 0.0)).magnitude() > 0.9 {
if choose_mat < 0.8 {
// 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(center, 0.2, Box::new(material::Lambertian::new(albedo)))));
+ 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(
+ center,
+ 0.2,
+ Box::new(material::Lambertian::new(albedo)),
+ )));
} else if choose_mat < 0.95 {
// metal
let albedo = utils::random_vector3(rng, 0.5, 1.0);
let fuzz = rng.gen_range(0.0, 0.5);
- scene.add(
- Box::new(sphere::Sphere::new(
- center, 0.2, Box::new(material::Metal::new(albedo, fuzz)))));
+ scene.add(Box::new(sphere::Sphere::new(
+ center,
+ 0.2,
+ Box::new(material::Metal::new(albedo, fuzz)),
+ )));
} else {
// glass
scene.add(Box::new(sphere::Sphere::new(
- center, 0.2, Box::new(material::Dielectric::new(1.5)))));
+ center,
+ 0.2,
+ Box::new(material::Dielectric::new(1.5)),
+ )));
}
}
}
}
scene.add(Box::new(sphere::Sphere::new(
- vec3(0.0, 1.0, 0.0), 1.0, Box::new(material::Dielectric::new(1.5)))));
+ vec3(0.0, 1.0, 0.0),
+ 1.0,
+ Box::new(material::Dielectric::new(1.5)),
+ )));
- scene.add(
- Box::new(sphere::Sphere::new(vec3(-4.0, 1.0, 0.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),
+ 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), 1.0, Box::new(material::Metal::new(vec3(0.7, 0.6, 0.5), 0.0)))));
+ scene.add(Box::new(sphere::Sphere::new(
+ vec3(4.0, 1.0, 0.0),
+ 1.0,
+ Box::new(material::Metal::new(vec3(0.7, 0.6, 0.5), 0.0)),
+ )));
scene
}
@@ -61,8 +84,8 @@ pub fn random_scene(rng: &mut ThreadRng) -> scene::Scene {
fn main() {
let image_width = 400;
let image_height = 200;
- let samples = 50;
- let threads = 1;
+ let samples = 400;
+ let threads = 4;
let max_depth = 50;
let aspect_ratio = image_width as f64 / image_height as f64;
@@ -76,10 +99,27 @@ fn main() {
let vup = vec3(0.0, 1.0, 0.0);
let dist_to_focus = 10.0;
let aperture = 0.1;
- let camera = camera::Camera::new(&lookfrom, &lookat, &vup,
- 20.0 * PI / 180.0, aspect_ratio, aperture, dist_to_focus);
+ let camera = camera::Camera::new(
+ &lookfrom,
+ &lookat,
+ &vup,
+ 20.0 * PI / 180.0,
+ aspect_ratio,
+ aperture,
+ dist_to_focus,
+ 0.0,
+ 1.0,
+ );
- render::render(&scene, &camera, image_height, image_width, samples, max_depth, threads);
+ render::render(
+ &scene,
+ &camera,
+ image_height,
+ image_width,
+ samples,
+ max_depth,
+ threads,
+ );
eprintln!("\nDone")
}
diff --git a/src/material.rs b/src/material.rs
index 42e8d0c..91e7c02 100644
--- a/src/material.rs
+++ b/src/material.rs
@@ -1,16 +1,16 @@
+use crate::hittable::Hit;
+use crate::ray::{NextRay, Ray};
+use crate::utils::{random_in_unit_sphere, random_unit_vector, reflect, refract, schlick};
use cgmath::prelude::*;
-use cgmath::{Vector3, vec3, dot};
+use cgmath::{dot, vec3, Vector3};
use rand::prelude::*;
-use crate::ray::{Ray, NextRay};
-use crate::hittable::Hit;
-use crate::utils::{random_unit_vector, random_in_unit_sphere, reflect, refract, schlick};
pub trait Material {
fn scatter(&self, rng: &mut ThreadRng, ray: &Ray, hit: &Hit) -> Option<NextRay>;
}
pub struct Lambertian {
- pub albedo: Vector3<f64>
+ pub albedo: Vector3<f64>,
}
impl Lambertian {
@@ -22,13 +22,16 @@ impl Lambertian {
impl Material for Lambertian {
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)))
+ Some(NextRay::new(
+ self.albedo,
+ Ray::new(hit.p, scatter_direction, 0.0),
+ ))
}
}
pub struct Metal {
pub albedo: Vector3<f64>,
- pub fuzz: f64
+ pub fuzz: f64,
}
impl Metal {
@@ -41,7 +44,11 @@ impl Metal {
impl Material for Metal {
fn scatter(&self, rng: &mut ThreadRng, ray: &Ray, hit: &Hit) -> Option<NextRay> {
let reflected = reflect(&ray.dir.normalize(), &hit.normal);
- let scattered = Ray::new(hit.p, reflected + self.fuzz * random_in_unit_sphere(rng));
+ let scattered = Ray::new(
+ hit.p,
+ reflected + self.fuzz * random_in_unit_sphere(rng),
+ 0.0,
+ );
if dot(scattered.dir, hit.normal) > 0.0 {
Some(NextRay::new(self.albedo, scattered))
} else {
@@ -51,7 +58,7 @@ impl Material for Metal {
}
pub struct Dielectric {
- pub ref_idx: f64
+ pub ref_idx: f64,
}
impl Dielectric {
@@ -63,24 +70,28 @@ impl Dielectric {
impl Material for Dielectric {
fn scatter(&self, rng: &mut ThreadRng, ray: &Ray, hit: &Hit) -> Option<NextRay> {
let attenuation = vec3(1.0, 1.0, 1.0);
- let etai_over_etat = if hit.front_face { 1.0 / self.ref_idx } else { self.ref_idx };
+ let etai_over_etat = if hit.front_face {
+ 1.0 / self.ref_idx
+ } else {
+ self.ref_idx
+ };
let unit_direction = ray.dir.normalize();
let cos_theta = f64::min(dot(-unit_direction, hit.normal), 1.0);
- let sin_theta = (1.0 - cos_theta*cos_theta).sqrt();
+ let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();
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)))
+ return Some(NextRay::new(attenuation, Ray::new(hit.p, reflected, 0.0)));
}
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)))
+ return Some(NextRay::new(attenuation, Ray::new(hit.p, reflected, 0.0)));
}
let refracted = refract(&unit_direction, &hit.normal, etai_over_etat);
- Some(NextRay::new(attenuation, Ray::new(hit.p, refracted)))
+ Some(NextRay::new(attenuation, Ray::new(hit.p, refracted, 0.0)))
}
}
diff --git a/src/ray.rs b/src/ray.rs
index 08fee78..e7fe583 100644
--- a/src/ray.rs
+++ b/src/ray.rs
@@ -2,12 +2,13 @@ use cgmath::Vector3;
pub struct Ray {
pub orig: Vector3<f64>,
- pub dir: Vector3<f64>
+ pub dir: Vector3<f64>,
+ pub time: f64,
}
impl Ray {
- pub fn new(orig: Vector3<f64>, dir: Vector3<f64>) -> Ray {
- Ray {orig, dir}
+ pub fn new(orig: Vector3<f64>, dir: Vector3<f64>, time: f64) -> Ray {
+ Ray { orig, dir, time }
}
pub fn at(&self, t: f64) -> Vector3<f64> {
@@ -17,7 +18,7 @@ impl Ray {
pub struct NextRay {
pub attenuation: Vector3<f64>,
- pub ray: Ray
+ pub ray: Ray,
}
impl NextRay {
diff --git a/src/render.rs b/src/render.rs
index 47c6698..c3d132a 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -1,20 +1,22 @@
+use crate::camera::Camera;
+use crate::hittable::Hittable;
+use crate::ray::Ray;
+use crate::scene::Scene;
+use crate::utils::print_colour;
use cgmath::prelude::*;
-use cgmath::{Vector3, vec3};
+use cgmath::{vec3, Vector3};
use rand::prelude::*;
use rayon::prelude::*;
use std::f64::INFINITY;
-use crate::camera::Camera;
-use crate::scene::Scene;
-use crate::utils::{print_colour};
-use crate::ray::Ray;
-use crate::hittable::Hittable;
fn ray_colour(rng: &mut ThreadRng, ray: &Ray, scene: &Scene, depth: i32) -> Vector3<f64> {
- if depth <= 0 { return vec3(0.0, 0.0, 0.0) }
+ if depth <= 0 {
+ return vec3(0.0, 0.0, 0.0);
+ }
if let Some(t) = scene.is_hit(ray, 0.001, INFINITY) {
if let Some(nray) = t.material.scatter(rng, ray, &t) {
- ray_colour(rng, &nray.ray, scene, depth-1).mul_element_wise(nray.attenuation)
+ ray_colour(rng, &nray.ray, scene, depth - 1).mul_element_wise(nray.attenuation)
} else {
vec3(0.0, 0.0, 0.0)
}
@@ -24,10 +26,19 @@ fn ray_colour(rng: &mut ThreadRng, ray: &Ray, scene: &Scene, depth: i32) -> Vect
}
}
-pub fn thread_render(world: &Scene, camera: &Camera, rng: &mut ThreadRng, image_height: i32,
- image_width: i32, samples: i32, max_depth: i32, i: i32, j: i32) -> Vector3<f64> {
+pub fn thread_render(
+ world: &Scene,
+ camera: &Camera,
+ rng: &mut ThreadRng,
+ image_height: i32,
+ image_width: i32,
+ samples: i32,
+ max_depth: i32,
+ i: i32,
+ j: i32,
+) -> Vector3<f64> {
let mut colour = vec3(0.0, 0.0, 0.0);
- for _ in 0 .. samples {
+ for _ in 0..samples {
let ru: f64 = rng.gen();
let rv: f64 = rng.gen();
let u = (i as f64 + ru) / image_width as f64;
@@ -38,19 +49,32 @@ pub fn thread_render(world: &Scene, camera: &Camera, rng: &mut ThreadRng, image_
colour
}
-pub fn render(world: &Scene, camera: &Camera, image_height: i32, image_width: i32,
- samples: i32, max_depth: i32, threads: i32) {
- for j in 0 .. image_height {
- eprint!("\rScanlines: {:3} / {:3}", j+1, image_height);
- for i in 0 .. image_width {
- let colours = (0 .. threads)
- .into_par_iter()
- .map(|_| {
- let mut trng = thread_rng();
- thread_render(
- world, camera, &mut trng, image_height, image_width,
- samples / threads, max_depth, i, j)
- });
+pub fn render(
+ world: &Scene,
+ camera: &Camera,
+ image_height: i32,
+ image_width: i32,
+ samples: i32,
+ max_depth: i32,
+ threads: i32,
+) {
+ for j in 0..image_height {
+ eprint!("\rScanlines: {:3} / {:3}", j + 1, image_height);
+ for i in 0..image_width {
+ let colours = (0..threads).into_par_iter().map(|_| {
+ let mut trng = thread_rng();
+ thread_render(
+ world,
+ camera,
+ &mut trng,
+ image_height,
+ image_width,
+ samples / threads,
+ max_depth,
+ i,
+ j,
+ )
+ });
let colour = colours.sum::<Vector3<f64>>();
print_colour(&colour, samples);
}
diff --git a/src/scene.rs b/src/scene.rs
index 0aa775c..215935a 100644
--- a/src/scene.rs
+++ b/src/scene.rs
@@ -1,13 +1,15 @@
-use crate::hittable::{Hittable, Hit};
+use crate::hittable::{Hit, Hittable};
use crate::ray::Ray;
pub struct Scene {
- objects: Vec<Box<dyn Hittable + std::marker::Sync>>
+ objects: Vec<Box<dyn Hittable + std::marker::Sync>>,
}
impl Scene {
pub fn new() -> Scene {
- Scene { objects: Vec::new() }
+ Scene {
+ objects: Vec::new(),
+ }
}
pub fn add(&mut self, obj: Box<dyn Hittable + std::marker::Sync>) {
diff --git a/src/sphere.rs b/src/sphere.rs
index f1c88b6..59ca498 100644
--- a/src/sphere.rs
+++ b/src/sphere.rs
@@ -1,19 +1,27 @@
-use cgmath::prelude::*;
-use cgmath::{Vector3, dot};
-use core::borrow::Borrow;
+use crate::hittable::{Hit, Hittable};
use crate::material::Material;
-use crate::hittable::{Hittable, Hit};
use crate::ray::Ray;
+use cgmath::prelude::*;
+use cgmath::{dot, Vector3};
+use core::borrow::Borrow;
pub struct Sphere {
center: Vector3<f64>,
radius: f64,
- material: Box<dyn Material + std::marker::Sync>
+ material: Box<dyn Material + std::marker::Sync>,
}
impl Sphere {
- pub fn new(center: Vector3<f64>, radius: f64, material: Box<dyn Material + std::marker::Sync>) -> Sphere {
- Sphere { center, radius, material }
+ pub fn new(
+ center: Vector3<f64>,
+ radius: f64,
+ material: Box<dyn Material + std::marker::Sync>,
+ ) -> Sphere {
+ Sphere {
+ center,
+ radius,
+ material,
+ }
}
}
@@ -23,16 +31,92 @@ impl Hittable for Sphere {
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;
+ 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(
+ center0: Vector3<f64>,
+ center1: Vector3<f64>,
+ time0: f64,
+ time1: f64,
+ radius: f64,
+ material: Box<dyn Material + std::marker::Sync>,
+ ) -> MovingSphere {
+ MovingSphere {
+ center0,
+ center1,
+ time0,
+ time1,
+ radius,
+ material,
+ }
+ }
+
+ pub fn center(&self, time: f64) -> Vector3<f64> {
+ self.center0
+ + ((time + self.time0) / (self.time0 + self.time1)) * (self.center1 - self.center0)
+ }
+}
+
+impl Hittable for MovingSphere {
+ 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();
+ 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()))
+ return Some(Hit::new(
+ ray,
+ soln,
+ (ray.at(soln) - self.center(ray.time)) / 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()))
+ return Some(Hit::new(
+ ray,
+ soln,
+ (ray.at(soln) - self.center(ray.time)) / self.radius,
+ self.material.borrow(),
+ ));
}
}
None
diff --git a/src/utils.rs b/src/utils.rs
index 659de7d..7e8c51f 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,51 +1,66 @@
use cgmath::prelude::*;
-use cgmath::{Vector3, vec3, dot};
+use cgmath::{dot, vec3, Vector3};
use rand::prelude::*;
use std::f64::consts::PI;
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
- if x < min { min }
- else if x > max { max }
- else { x }
+ if x < min {
+ min
+ } else if x > max {
+ max
+ } else {
+ x
+ }
}
pub fn print_colour(colour: &Vector3<f64>, samples: i32) {
let scolour = colour.map(|x| (x / samples as f64).sqrt());
- println!("{} {} {}"
- , (256.0 * clamp(scolour.x, 0.0, 0.999)) as i32
- , (256.0 * clamp(scolour.y, 0.0, 0.999)) as i32
- , (256.0 * clamp(scolour.z, 0.0, 0.999)) as i32)
+ println!(
+ "{} {} {}",
+ (256.0 * clamp(scolour.x, 0.0, 0.999)) as i32,
+ (256.0 * clamp(scolour.y, 0.0, 0.999)) as i32,
+ (256.0 * clamp(scolour.z, 0.0, 0.999)) as i32
+ )
}
pub fn random_vector3(rng: &mut ThreadRng, min: f64, max: f64) -> Vector3<f64> {
- vec3(rng.gen_range(min, max), rng.gen_range(min, max), rng.gen_range(min, max))
+ vec3(
+ rng.gen_range(min, max),
+ rng.gen_range(min, max),
+ rng.gen_range(min, max),
+ )
}
pub fn random_in_unit_sphere(rng: &mut ThreadRng) -> Vector3<f64> {
loop {
let p = random_vector3(rng, -1.0, 1.0);
- if p.magnitude2() <= 1.0 { return p }
+ if p.magnitude2() <= 1.0 {
+ return p;
+ }
}
}
pub fn random_unit_vector(rng: &mut ThreadRng) -> Vector3<f64> {
- let a = rng.gen_range(0.0, 2.0*PI);
+ let a = rng.gen_range(0.0, 2.0 * PI);
let z = rng.gen_range(-1.0, 1.0);
- let r = ((1.0 - z*z) as f64).sqrt();
- vec3(r*a.cos(), r*a.sin(), z)
+ let r = ((1.0 - z * z) as f64).sqrt();
+ vec3(r * a.cos(), r * a.sin(), z)
}
pub fn random_in_hemisphere(rng: &mut ThreadRng, normal: &Vector3<f64>) -> Vector3<f64> {
let in_unit_sphere = random_in_unit_sphere(rng);
- if dot(in_unit_sphere, *normal) > 0.0 { in_unit_sphere }
- else { -in_unit_sphere }
+ if dot(in_unit_sphere, *normal) > 0.0 {
+ in_unit_sphere
+ } else {
+ -in_unit_sphere
+ }
}
pub fn random_in_unit_disk(rng: &mut ThreadRng) -> Vector3<f64> {
loop {
let p = vec3(rng.gen_range(-1.0, 1.0), rng.gen_range(-1.0, 1.0), 0.0);
if p.magnitude2() < 1.0 {
- return p
+ return p;
}
}
}
@@ -56,13 +71,13 @@ pub fn reflect(v: &Vector3<f64>, n: &Vector3<f64>) -> Vector3<f64> {
pub fn refract(uv: &Vector3<f64>, n: &Vector3<f64>, etai_over_etat: f64) -> Vector3<f64> {
let cos_theta = dot(-1.0 * uv, *n);
- let r_out_parallel = etai_over_etat * (uv + cos_theta*n);
+ let r_out_parallel = etai_over_etat * (uv + cos_theta * n);
let r_out_perp = -(1.0 - r_out_parallel.magnitude2()).sqrt() * n;
r_out_parallel + r_out_perp
}
pub fn schlick(cosine: f64, ref_idx: f64) -> f64 {
let r0 = (1.0 - ref_idx) / (1.0 + ref_idx);
- let r0sq = r0*r0;
+ let r0sq = r0 * r0;
r0sq + (1.0 - r0) * (1.0 - cosine).powi(5)
}