M Cargo.lock => Cargo.lock +226 -0
@@ 1,12 1,90 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "cc"
+version = "1.0.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+
+[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
+name = "crossbeam-channel"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d60ab4a8dba064f2fbb5aa270c28da5cf4bbd0e72dae1140a6b0353a779dbe00"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "lazy_static",
+ "loom",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bae8f328835f8f5a6ceb6a7842a7f2d0c03692adb5c889347235d59194731fe3"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "lazy_static",
+ "loom",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "generator"
+version = "0.6.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc"
+dependencies = [
+ "cc",
+ "libc",
+ "log",
+ "rustc_version",
+ "winapi",
+]
+
+[[package]]
name = "getrandom"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 18,12 96,75 @@ dependencies = [
]
[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
name = "libc"
version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "loom"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d44c73b4636e497b4917eb21c33539efa3816741a2d3ff26c6316f1b529481a4"
+dependencies = [
+ "cfg-if",
+ "generator",
+ "scoped-tls",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 73,11 214,96 @@ dependencies = [
name = "ray_tracing_in_one_weekend"
version = "0.1.0"
dependencies = [
+ "itertools",
"rand",
+ "rayon",
+]
+
+[[package]]
+name = "rayon"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
+dependencies = [
+ "autocfg",
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser",
]
[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
+[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
M Cargo.toml => Cargo.toml +2 -0
@@ 8,6 8,8 @@ edition = "2018"
[dependencies]
rand = "0.8"
+itertools="0.10"
+rayon = "1.5"
[profile.dev]
lto=true
M src/hittable_list.rs => src/hittable_list.rs +2 -2
@@ 4,7 4,7 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct HittableList {
- objects: Vec<Arc<dyn Hittable>>,
+ objects: Vec<Arc<dyn Hittable + Send + Sync>>,
}
impl HittableList {
@@ 12,7 12,7 @@ impl HittableList {
HittableList { objects: vec![] }
}
- pub fn add(&mut self, object: Arc<dyn Hittable>) {
+ pub fn add(&mut self, object: Arc<dyn Hittable + Send + Sync>) {
self.objects.push(object);
}
}
A src/image.rs => src/image.rs +59 -0
@@ 0,0 1,59 @@
+use crate::{Color};
+use std::collections::HashMap;
+use std::sync::Mutex;
+
+pub struct Image {
+ pixels: Mutex<HashMap<(usize, usize), Color>>,
+ samples_per_pixel: usize,
+ w: usize,
+ h: usize,
+}
+
+impl Image {
+ pub fn new(w: usize, h: usize, samples_per_pixel: usize) -> Self {
+ Self {
+ pixels: Default::default(),
+ samples_per_pixel,
+ w, h
+ }
+ }
+
+ pub fn set(&self, x: usize, y: usize, val: Color) {
+ self.pixels.lock().unwrap().insert((x, y), val);
+ let len = self.pixels.lock().unwrap().len() as f64;
+ let total = (self.w * self.h) as f64;
+ eprint!("\r{:.1}%", 100.0 * len / total);
+ }
+
+ pub fn to_ppm(&self, out: &mut impl std::io::Write) -> std::io::Result<()> {
+ let mut pixels : Vec<((_, _), Color)> = self.pixels.lock().unwrap().iter().map(|(p, c)| (p.clone(), c.clone())).collect();
+ pixels.sort_by(|l, r| l.0.0.cmp(&r.0.0));
+ pixels.sort_by(|l, r| r.0.1.cmp(&l.0.1));
+ write!(out, "P3\n{} {}\n255\n", self.w, self.h)?;
+ for p in pixels {
+ write_color(out, p.1, self.samples_per_pixel)?;
+ }
+ Ok(())
+ }
+}
+
+fn write_color(out: &mut impl std::io::Write, pixel_color: Color, samples_per_pixel: usize) -> std::io::Result<()> {
+ let mut r = pixel_color.x();
+ let mut g = pixel_color.y();
+ let mut b = pixel_color.z();
+
+ // Divide the color by the number of samples.
+ let scale = 1.0 / samples_per_pixel as f64;
+ r = (scale * r).sqrt();
+ g = (scale * g).sqrt();
+ b = (scale * b).sqrt();
+
+ write!(
+ out,
+ "{} {} {}\n",
+ (256.0 * r.clamp(0.0, 0.999)).round() as usize,
+ (256.0 * g.clamp(0.0, 0.999)).round() as usize,
+ (256.0 * b.clamp(0.0, 0.999)).round() as usize,
+ )
+}
+
M src/main.rs => src/main.rs +30 -23
@@ 1,3 1,6 @@
+use itertools::Itertools;
+use rayon::prelude::*;
+pub use std::f64::consts::PI;
use std::sync::Arc;
mod vec3;
@@ 24,7 27,8 @@ use camera::*;
mod material;
use material::*;
-pub use std::f64::consts::PI;
+mod image;
+use image::*;
fn ray_color(r: &Ray, world: &dyn Hittable, depth: isize) -> Color {
// If we've exceeded the ray bounce limit, no more light is gathered.
@@ 43,9 47,6 @@ fn ray_color(r: &Ray, world: &dyn Hittable, depth: isize) -> Color {
}
fn main() {
- let stdout = std::io::stdout();
- let mut handle = stdout.lock();
-
// Image
let aspect_ratio = 3.0 / 2.0;
let image_width = 1200;
@@ 73,29 74,35 @@ fn main() {
);
// Render
-
- print!("P3\n{} {}\n255\n", image_width, image_height);
-
- for j in (0..=(image_height - 1)).rev() {
- eprint!("\rScanlines remaining: {} ", j);
- for i in 0..image_width {
- let mut pixel_color = Color::default();
- for _ in 0..samples_per_pixel {
- let u = (i as f64 + random_double()) / (image_width - 1) as f64;
- let v = (j as f64 + random_double()) / (image_height - 1) as f64;
- let r = cam.get_ray(u, v);
- pixel_color += ray_color(&r, &world, max_depth);
- }
- write_color(&mut handle, pixel_color, samples_per_pixel);
+ let img = Image::new(image_width, image_height as usize, samples_per_pixel);
+
+ let aux = move |i: usize, j: usize| {
+ let mut pixel_color = Color::default();
+ for _ in 0..samples_per_pixel {
+ let u = (i as f64 + random_double()) / (image_width - 1) as f64;
+ let v = (j as f64 + random_double()) / (image_height - 1) as f64;
+ let r = cam.get_ray(u, v);
+ pixel_color += ray_color(&r, &world, max_depth);
}
- }
- eprintln!("\nDone!");
+ pixel_color
+ };
+
+ let stdout = std::io::stdout();
+
+ (0..image_height)
+ .cartesian_product(0..image_width)
+ .collect::<Vec<_>>()
+ .par_iter()
+ .for_each(|(j, i)| img.set(*i, *j as usize, aux(*i, *j as usize)));
+
+ let r = img.to_ppm(&mut stdout.lock());
+ eprintln!("\nDone: {:?}", r);
}
fn random_scene() -> HittableList {
let mut world = HittableList::empty();
- let ground_material: MaterialPtr = Arc::new(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
+ let ground_material = Arc::new(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
world.add(Arc::new(Sphere::new(
Point3::new(0., -1000., 0.),
1000.,
@@ 115,13 122,13 @@ fn random_scene() -> HittableList {
if choose_mat < 0.8 {
// diffuse
let albedo = Color::random() * Color::random();
- let sphere_material: MaterialPtr = Arc::new(Lambertian::new(albedo));
+ let sphere_material = Arc::new(Lambertian::new(albedo));
world.add(Arc::new(Sphere::new(center, 0.2, sphere_material)));
} else if choose_mat < 0.95 {
// metal
let albedo = Color::random_range(0.5..1.);
let fuzz = random_double_range(0f64..0.5);
- let sphere_material: MaterialPtr = Arc::new(Metal::new(albedo, fuzz));
+ let sphere_material = Arc::new(Metal::new(albedo, fuzz));
world.add(Arc::new(Sphere::new(center, 0.2, sphere_material)));
} else {
// glass
M src/material.rs => src/material.rs +1 -1
@@ 8,7 8,7 @@ pub trait Material: Debug {
fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> Option<(Color, Ray)>;
}
-pub type MaterialPtr = std::sync::Arc<dyn Material>;
+pub type MaterialPtr = std::sync::Arc<dyn Material + Send + Sync>;
#[derive(Debug)]
pub struct Lambertian {
M src/vec3.rs => src/vec3.rs +0 -21
@@ 200,27 200,6 @@ pub fn unit_vector(v: Vec3) -> Vec3 {
v / v.length()
}
-pub fn write_color(out: &mut impl std::io::Write, pixel_color: Color, samples_per_pixel: usize) {
- let mut r = pixel_color.x();
- let mut g = pixel_color.y();
- let mut b = pixel_color.z();
-
- // Divide the color by the number of samples.
- let scale = 1.0 / samples_per_pixel as f64;
- r = (scale * r).sqrt();
- g = (scale * g).sqrt();
- b = (scale * b).sqrt();
-
- write!(
- out,
- "{} {} {}\n",
- (256.0 * r.clamp(0.0, 0.999)).round() as usize,
- (256.0 * g.clamp(0.0, 0.999)).round() as usize,
- (256.0 * b.clamp(0.0, 0.999)).round() as usize,
- )
- .unwrap();
-}
-
pub fn random_in_unit_sphere() -> Vec3 {
loop {
let p = Vec3::random_range(-1.0..1.0);