aboutsummaryrefslogtreecommitdiffstats
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
parentdd5ac7c5fe336e9cac794cfa72d139613a99b466 (diff)
downloadleela-495d1c9c113098f24767b595c7e830f0fa8bc991.tar.gz
leela-495d1c9c113098f24767b595c7e830f0fa8bc991.zip
Format all the files and add moving sphere
-rw-r--r--Cargo.lock75
-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
11 files changed, 358 insertions, 150 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3416654..20543d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,9 +17,9 @@ checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "autocfg"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
@@ -54,6 +54,16 @@ dependencies = [
]
[[package]]
+name = "crossbeam-channel"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
+dependencies = [
+ "crossbeam-utils",
+ "maybe-uninit",
+]
+
+[[package]]
name = "crossbeam-deque"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -70,7 +80,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
"cfg-if",
"crossbeam-utils",
"lazy_static",
@@ -80,31 +90,21 @@ dependencies = [
]
[[package]]
-name = "crossbeam-queue"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
-dependencies = [
- "cfg-if",
- "crossbeam-utils",
-]
-
-[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
"cfg-if",
"lazy_static",
]
[[package]]
name = "either"
-version = "1.5.3"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fuchsia-cprng"
@@ -114,9 +114,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "getrandom"
-version = "0.1.14"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
dependencies = [
"cfg-if",
"libc",
@@ -125,9 +125,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.1.12"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
+checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
dependencies = [
"libc",
]
@@ -149,9 +149,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.68"
+version = "0.2.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
+checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
[[package]]
name = "maybe-uninit"
@@ -161,20 +161,20 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]]
name = "memoffset"
-version = "0.5.4"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
+checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
]
[[package]]
name = "num-traits"
-version = "0.2.11"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
+checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg 1.0.1",
]
[[package]]
@@ -189,9 +189,9 @@ dependencies = [
[[package]]
name = "ppv-lite86"
-version = "0.2.6"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
+checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
[[package]]
name = "rand"
@@ -342,10 +342,11 @@ dependencies = [
[[package]]
name = "rayon"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
+checksum = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
dependencies = [
+ "autocfg 1.0.1",
"crossbeam-deque",
"either",
"rayon-core",
@@ -353,12 +354,12 @@ dependencies = [
[[package]]
name = "rayon-core"
-version = "1.7.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
+checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
dependencies = [
+ "crossbeam-channel",
"crossbeam-deque",
- "crossbeam-queue",
"crossbeam-utils",
"lazy_static",
"num_cpus",
@@ -387,9 +388,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
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)
}