multithreading && code cleanup
This commit is contained in:
@@ -6,4 +6,5 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "*"
|
rand = "0.7.0"
|
||||||
|
rayon = "1.8"
|
||||||
16
src/color.rs
16
src/color.rs
@@ -1,8 +1,6 @@
|
|||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use crate::{vec3::*, rtweekend::clamp};
|
use crate::{vec3::*, rtweekend::clamp};
|
||||||
|
|
||||||
fn get_scaled_color_components(c: Color, samples_per_pixel: i32) -> (u8, u8, u8) {
|
pub fn get_scaled_color_components(c: Color, samples_per_pixel: i32) -> (u8, u8, u8) {
|
||||||
let r = c.x();
|
let r = c.x();
|
||||||
let g = c.y();
|
let g = c.y();
|
||||||
let b = c.z();
|
let b = c.z();
|
||||||
@@ -18,16 +16,4 @@ fn get_scaled_color_components(c: Color, samples_per_pixel: i32) -> (u8, u8, u8)
|
|||||||
(255.0 * clamp(g, 0.0, 1.0)) as u8,
|
(255.0 * clamp(g, 0.0, 1.0)) as u8,
|
||||||
(255.0 * clamp(b, 0.0, 1.0)) as u8,
|
(255.0 * clamp(b, 0.0, 1.0)) as u8,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_color<T: Write>(writer: &mut T, pixel_color: Color, samples_per_pixel: i32) {
|
|
||||||
let (r, g, b) = get_scaled_color_components(pixel_color, samples_per_pixel);
|
|
||||||
write!(writer, "{r} {g} {b} ").expect("Can write pixel data");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_color_bin<T: Write>(writer: &mut T, pixel_color: Color, samples_per_pixel: i32) {
|
|
||||||
let (r, g, b) = get_scaled_color_components(pixel_color, samples_per_pixel);
|
|
||||||
let binary_data = [r, g, b];
|
|
||||||
|
|
||||||
writer.write(&binary_data).expect("Can write binary pixel data!");
|
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,6 @@ impl HitRecord<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Hittable {
|
pub trait Hittable: Send + Sync {
|
||||||
fn hit(&mut self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord>;
|
fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord<'_>>;
|
||||||
}
|
}
|
||||||
@@ -19,11 +19,11 @@ impl HittableList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hittable for HittableList {
|
impl Hittable for HittableList {
|
||||||
fn hit(&mut self, r: &crate::ray::Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
fn hit(&self, r: &crate::ray::Ray, t_min: f64, t_max: f64) -> Option<HitRecord<'_>> {
|
||||||
let mut temp_rec = None;
|
let mut temp_rec = None;
|
||||||
let mut closest_so_far = t_max;
|
let mut closest_so_far = t_max;
|
||||||
|
|
||||||
for object in &mut self.objects {
|
for object in &self.objects {
|
||||||
if let Some(rec) = object.hit(r, t_min, closest_so_far) {
|
if let Some(rec) = object.hit(r, t_min, closest_so_far) {
|
||||||
closest_so_far = rec.t;
|
closest_so_far = rec.t;
|
||||||
temp_rec = Some(rec);
|
temp_rec = Some(rec);
|
||||||
|
|||||||
153
src/main.rs
153
src/main.rs
@@ -1,37 +1,51 @@
|
|||||||
pub mod vec3;
|
pub mod camera;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod ray;
|
|
||||||
pub mod sphere;
|
|
||||||
pub mod hittable;
|
pub mod hittable;
|
||||||
pub mod hittable_list;
|
pub mod hittable_list;
|
||||||
pub mod rtweekend;
|
|
||||||
pub mod camera;
|
|
||||||
pub mod material;
|
pub mod material;
|
||||||
|
pub mod ray;
|
||||||
|
pub mod rtweekend;
|
||||||
|
pub mod sphere;
|
||||||
|
pub mod vec3;
|
||||||
|
|
||||||
use std::{io::{BufWriter, Write, stdout}, fs::File, time::Instant};
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
io::{stdout, Write},
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
material::*,
|
camera::*,
|
||||||
color::*,
|
color::*,
|
||||||
sphere::*,
|
|
||||||
rtweekend::*,
|
|
||||||
hittable_list::*,
|
|
||||||
vec3::*,
|
|
||||||
ray::*,
|
|
||||||
hittable::*,
|
hittable::*,
|
||||||
camera::*, material::{Lambertian, Dielectric},
|
hittable_list::*,
|
||||||
|
material::*,
|
||||||
|
material::{Dielectric, Lambertian},
|
||||||
|
ray::*,
|
||||||
|
rtweekend::*,
|
||||||
|
sphere::*,
|
||||||
|
vec3::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn random_scene() -> HittableList {
|
fn random_scene() -> HittableList {
|
||||||
let mut world = HittableList::new_empty();
|
let mut world = HittableList::new_empty();
|
||||||
|
|
||||||
static GROUND_MATERIAL: Lambertian = Lambertian::new(Color::new(0.5, 0.5, 0.5));
|
static GROUND_MATERIAL: Lambertian = Lambertian::new(Color::new(0.5, 0.5, 0.5));
|
||||||
world.add(Box::new(Sphere::new(Point3::new(0.0, -1000.0, 0.0), 1000.0, &GROUND_MATERIAL)));
|
world.add(Box::new(Sphere::new(
|
||||||
|
Point3::new(0.0, -1000.0, 0.0),
|
||||||
|
1000.0,
|
||||||
|
&GROUND_MATERIAL,
|
||||||
|
)));
|
||||||
|
|
||||||
for a in 0..12 {
|
for a in 0..12 {
|
||||||
for b in 0..12 {
|
for b in 0..12 {
|
||||||
let choose_mat = random_f64();
|
let choose_mat = random_f64();
|
||||||
let center = Point3::new(a as f64 + 0.9*random_f64(), 0.2, b as f64 + 0.9*random_f64());
|
let center = Point3::new(
|
||||||
|
a as f64 + 0.9 * random_f64(),
|
||||||
|
0.2,
|
||||||
|
b as f64 + 0.9 * random_f64(),
|
||||||
|
);
|
||||||
|
|
||||||
if (center - Point3::new(4.0, 0.2, 0.0)).length() > 0.9 {
|
if (center - Point3::new(4.0, 0.2, 0.0)).length() > 0.9 {
|
||||||
if choose_mat < 0.8 {
|
if choose_mat < 0.8 {
|
||||||
@@ -50,18 +64,30 @@ fn random_scene() -> HittableList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MATERIAL1: Dielectric = Dielectric::new(1.5);
|
static MATERIAL1: Dielectric = Dielectric::new(1.5);
|
||||||
world.add(Box::new(Sphere::new(Point3::new(0.0, 1.0, 0.0), 1.0, &MATERIAL1)));
|
world.add(Box::new(Sphere::new(
|
||||||
|
Point3::new(0.0, 1.0, 0.0),
|
||||||
|
1.0,
|
||||||
|
&MATERIAL1,
|
||||||
|
)));
|
||||||
|
|
||||||
static MATERIAL2: Lambertian = Lambertian::new(Color::new(0.4, 0.2, 0.1));
|
static MATERIAL2: Lambertian = Lambertian::new(Color::new(0.4, 0.2, 0.1));
|
||||||
world.add(Box::new(Sphere::new(Point3::new(-4.0, 1.0, 0.0), 1.0, &MATERIAL2)));
|
world.add(Box::new(Sphere::new(
|
||||||
|
Point3::new(-4.0, 1.0, 0.0),
|
||||||
|
1.0,
|
||||||
|
&MATERIAL2,
|
||||||
|
)));
|
||||||
|
|
||||||
static MATERIAL3: Metal = Metal::new(Color::new(0.7, 0.6, 0.5), 0.0);
|
static MATERIAL3: Metal = Metal::new(Color::new(0.7, 0.6, 0.5), 0.0);
|
||||||
world.add(Box::new(Sphere::new(Point3::new(4.0, 1.0, 0.0), 1.0, &MATERIAL3)));
|
world.add(Box::new(Sphere::new(
|
||||||
|
Point3::new(4.0, 1.0, 0.0),
|
||||||
|
1.0,
|
||||||
|
&MATERIAL3,
|
||||||
|
)));
|
||||||
|
|
||||||
world
|
world
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray_color(r: Ray, world: &mut dyn Hittable, depth: i32) -> Color {
|
fn ray_color(r: Ray, world: &dyn Hittable, depth: i32) -> Color {
|
||||||
// Limit the bounces
|
// Limit the bounces
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return Color::new(0.0, 0.0, 0.0);
|
return Color::new(0.0, 0.0, 0.0);
|
||||||
@@ -71,8 +97,11 @@ fn ray_color(r: Ray, world: &mut dyn Hittable, depth: i32) -> Color {
|
|||||||
let mut scattered = Ray::new_empty();
|
let mut scattered = Ray::new_empty();
|
||||||
let mut attenuation = Color::new_empty();
|
let mut attenuation = Color::new_empty();
|
||||||
|
|
||||||
if rec.mat_ptr.scatter(r, rec, &mut attenuation, &mut scattered) {
|
if rec
|
||||||
return attenuation * ray_color(scattered, world, depth - 1);
|
.mat_ptr
|
||||||
|
.scatter(r, rec, &mut attenuation, &mut scattered)
|
||||||
|
{
|
||||||
|
return attenuation * ray_color(scattered, world, depth - 1);
|
||||||
}
|
}
|
||||||
return Color::new_empty();
|
return Color::new_empty();
|
||||||
}
|
}
|
||||||
@@ -86,19 +115,19 @@ fn ray_color(r: Ray, world: &mut dyn Hittable, depth: i32) -> Color {
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Image
|
// Image
|
||||||
let aspect_ratio: f64 = 1.0 / 1.0;
|
let aspect_ratio: f64 = 1.0 / 1.0;
|
||||||
let image_width: i32 = 1000;
|
let image_height: i32 = 1000;
|
||||||
let image_height: i32 = (image_width as f64 / aspect_ratio as f64) as i32;
|
let image_width: i32 = (image_height as f64 / aspect_ratio as f64) as i32;
|
||||||
let samples_per_pixel: i32 = 200;
|
let samples_per_pixel: i32 = 50;
|
||||||
let max_depth: i32 = 4;
|
let max_depth: i32 = 4;
|
||||||
|
|
||||||
// World
|
// World
|
||||||
let mut world = random_scene();
|
let world = random_scene();
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
let lookfrom = Point3::new(-13.0, 2.0, 3.0);
|
let lookfrom = Point3::new(-13.0, 2.0, 3.0);
|
||||||
let lookat = Point3::new(0.0, 0.0, 0.0);
|
let lookat = Point3::new(0.0, 0.0, 0.0);
|
||||||
let vup = Vec3::new(0.0, 1.0, 0.0);
|
let vup = Vec3::new(0.0, 1.0, 0.0);
|
||||||
let dist_to_focus = 10.0;//(lookfrom-lookat).length_squared();
|
let dist_to_focus = 10.0; //(lookfrom-lookat).length_squared();
|
||||||
|
|
||||||
let cam = Camera::new(
|
let cam = Camera::new(
|
||||||
lookfrom,
|
lookfrom,
|
||||||
@@ -107,37 +136,51 @@ fn main() {
|
|||||||
30.0,
|
30.0,
|
||||||
aspect_ratio,
|
aspect_ratio,
|
||||||
0.0,
|
0.0,
|
||||||
dist_to_focus
|
dist_to_focus,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
//let mut rng = rand::thread_rng();
|
rayon::ThreadPoolBuilder::new()
|
||||||
let now = Instant::now();
|
.num_threads(11)
|
||||||
let mut file = BufWriter::new(File::create("img.ppm").expect("File creation failed"));
|
.build_global()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
write!(file, "P6\n{image_width} {image_height}\n255\n").expect("Error while writing Magic Byte");
|
let mut buffer = vec![0u8; (image_width * image_height * 3) as usize];
|
||||||
|
|
||||||
for j in (0..image_width).rev() {
|
let rows_completed = AtomicUsize::new(0);
|
||||||
for i in 0..image_height {
|
let total_rows = image_height as usize;
|
||||||
let mut pixel_color = Color::new(0.0, 0.0, 0.0);
|
|
||||||
|
buffer
|
||||||
for _ in 0..samples_per_pixel {
|
.par_chunks_mut((image_width * 3) as usize)
|
||||||
let u = (i as f64 + random_f64()) / (image_width - 1) as f64;
|
.enumerate()
|
||||||
let v = (j as f64 + random_f64()) / (image_height - 1) as f64;
|
.for_each(|(index, row_slice)| {
|
||||||
let r: Ray = cam.get_ray(u, v);
|
let j = image_height - 1 - index as i32;
|
||||||
pixel_color += ray_color(r, &mut world, max_depth)
|
|
||||||
|
for i in 0..image_width {
|
||||||
|
let mut pixel_color = Color::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
for _ in 0..samples_per_pixel {
|
||||||
|
let u = (i as f64 + random_f64()) / (image_width - 1) as f64;
|
||||||
|
let v = (j as f64 + random_f64()) / (image_height - 1) as f64;
|
||||||
|
let r = cam.get_ray(u, v);
|
||||||
|
pixel_color += ray_color(r, &world, max_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ir, ig, ib) = get_scaled_color_components(pixel_color, samples_per_pixel);
|
||||||
|
|
||||||
|
row_slice[(i as usize) * 3] = ir;
|
||||||
|
row_slice[(i as usize) * 3 + 1] = ig;
|
||||||
|
row_slice[(i as usize) * 3 + 2] = ib;
|
||||||
}
|
}
|
||||||
write_color_bin(&mut file, pixel_color, samples_per_pixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
print!(
|
// progress
|
||||||
"[ {:.2} % ]\r",
|
let completed = rows_completed.fetch_add(1, Ordering::Relaxed) + 1;
|
||||||
(1.0 - ((j + 1) as f64 / image_width as f64)) * 100.0
|
if completed % 10 == 0 || completed == total_rows {
|
||||||
);
|
print!(
|
||||||
stdout().flush().expect("Can flush stdout");
|
"\r[ {:.2} % ] Rendering...",
|
||||||
}
|
(completed as f64 / total_rows as f64) * 100.0
|
||||||
println!("Took {:.6}ms", now.elapsed().as_millis());
|
);
|
||||||
println!("Took {:.6}s", now.elapsed().as_secs_f64());
|
let _ = stdout().flush();
|
||||||
println!("Took {:.6}m", now.elapsed().as_secs_f64() / 60.0);
|
}
|
||||||
println!("Took {:.6}h", now.elapsed().as_secs_f64() / 3600.0);
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use crate::vec3::{Color, random_unit_vector, reflect, refract};
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
pub trait Material {
|
pub trait Material: Send + Sync {
|
||||||
fn scatter(&self, r_in: Ray, rec: HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
|
fn scatter(&self, r_in: Ray, rec: HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub fn random_f64() -> f64 {
|
|||||||
|
|
||||||
// PLEASE CHANGE
|
// PLEASE CHANGE
|
||||||
pub fn random_range_f64(min: f64, max: f64) -> f64 {
|
pub fn random_range_f64(min: f64, max: f64) -> f64 {
|
||||||
rand::thread_rng().gen_range(min..=max)
|
rand::thread_rng().gen_range(min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
|
pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ impl Sphere<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hittable for Sphere<'_> {
|
impl Hittable for Sphere<'_> {
|
||||||
fn hit(&mut self, r: &crate::ray::Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
fn hit(&self, r: &crate::ray::Ray, t_min: f64, t_max: f64) -> Option<HitRecord<'_>> {
|
||||||
let oc = r.origin() - self.center;
|
let oc = r.origin() - self.center;
|
||||||
let a = r.direction().length_squared();
|
let a = r.direction().length_squared();
|
||||||
let half_b = oc.dot(&r.direction());
|
let half_b = oc.dot(&r.direction());
|
||||||
|
|||||||
Reference in New Issue
Block a user