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
|
||||
|
||||
[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};
|
||||
|
||||
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 g = c.y();
|
||||
let b = c.z();
|
||||
@@ -19,15 +17,3 @@ fn get_scaled_color_components(c: Color, samples_per_pixel: i32) -> (u8, u8, 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 {
|
||||
fn hit(&mut self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord>;
|
||||
pub trait Hittable: Send + Sync {
|
||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord<'_>>;
|
||||
}
|
||||
@@ -19,11 +19,11 @@ impl 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 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) {
|
||||
closest_so_far = rec.t;
|
||||
temp_rec = Some(rec);
|
||||
|
||||
127
src/main.rs
127
src/main.rs
@@ -1,37 +1,51 @@
|
||||
pub mod vec3;
|
||||
pub mod camera;
|
||||
pub mod color;
|
||||
pub mod ray;
|
||||
pub mod sphere;
|
||||
pub mod hittable;
|
||||
pub mod hittable_list;
|
||||
pub mod rtweekend;
|
||||
pub mod camera;
|
||||
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::{
|
||||
material::*,
|
||||
camera::*,
|
||||
color::*,
|
||||
sphere::*,
|
||||
rtweekend::*,
|
||||
hittable_list::*,
|
||||
vec3::*,
|
||||
ray::*,
|
||||
hittable::*,
|
||||
camera::*, material::{Lambertian, Dielectric},
|
||||
hittable_list::*,
|
||||
material::*,
|
||||
material::{Dielectric, Lambertian},
|
||||
ray::*,
|
||||
rtweekend::*,
|
||||
sphere::*,
|
||||
vec3::*,
|
||||
};
|
||||
|
||||
fn random_scene() -> HittableList {
|
||||
let mut world = HittableList::new_empty();
|
||||
|
||||
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 b in 0..12 {
|
||||
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 choose_mat < 0.8 {
|
||||
@@ -50,18 +64,30 @@ fn random_scene() -> HittableList {
|
||||
}
|
||||
|
||||
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));
|
||||
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);
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
if depth <= 0 {
|
||||
return Color::new(0.0, 0.0, 0.0);
|
||||
@@ -71,7 +97,10 @@ fn ray_color(r: Ray, world: &mut dyn Hittable, depth: i32) -> Color {
|
||||
let mut scattered = Ray::new_empty();
|
||||
let mut attenuation = Color::new_empty();
|
||||
|
||||
if rec.mat_ptr.scatter(r, rec, &mut attenuation, &mut scattered) {
|
||||
if rec
|
||||
.mat_ptr
|
||||
.scatter(r, rec, &mut attenuation, &mut scattered)
|
||||
{
|
||||
return attenuation * ray_color(scattered, world, depth - 1);
|
||||
}
|
||||
return Color::new_empty();
|
||||
@@ -86,13 +115,13 @@ fn ray_color(r: Ray, world: &mut dyn Hittable, depth: i32) -> Color {
|
||||
fn main() {
|
||||
// Image
|
||||
let aspect_ratio: f64 = 1.0 / 1.0;
|
||||
let image_width: i32 = 1000;
|
||||
let image_height: i32 = (image_width as f64 / aspect_ratio as f64) as i32;
|
||||
let samples_per_pixel: i32 = 200;
|
||||
let image_height: i32 = 1000;
|
||||
let image_width: i32 = (image_height as f64 / aspect_ratio as f64) as i32;
|
||||
let samples_per_pixel: i32 = 50;
|
||||
let max_depth: i32 = 4;
|
||||
|
||||
// World
|
||||
let mut world = random_scene();
|
||||
let world = random_scene();
|
||||
|
||||
// Camera
|
||||
let lookfrom = Point3::new(-13.0, 2.0, 3.0);
|
||||
@@ -107,37 +136,51 @@ fn main() {
|
||||
30.0,
|
||||
aspect_ratio,
|
||||
0.0,
|
||||
dist_to_focus
|
||||
dist_to_focus,
|
||||
);
|
||||
|
||||
// Render
|
||||
//let mut rng = rand::thread_rng();
|
||||
let now = Instant::now();
|
||||
let mut file = BufWriter::new(File::create("img.ppm").expect("File creation failed"));
|
||||
rayon::ThreadPoolBuilder::new()
|
||||
.num_threads(11)
|
||||
.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() {
|
||||
for i in 0..image_height {
|
||||
let rows_completed = AtomicUsize::new(0);
|
||||
let total_rows = image_height as usize;
|
||||
|
||||
buffer
|
||||
.par_chunks_mut((image_width * 3) as usize)
|
||||
.enumerate()
|
||||
.for_each(|(index, row_slice)| {
|
||||
let j = image_height - 1 - index as i32;
|
||||
|
||||
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: Ray = cam.get_ray(u, v);
|
||||
pixel_color += ray_color(r, &mut world, max_depth)
|
||||
}
|
||||
write_color_bin(&mut file, pixel_color, samples_per_pixel);
|
||||
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;
|
||||
}
|
||||
|
||||
// progress
|
||||
let completed = rows_completed.fetch_add(1, Ordering::Relaxed) + 1;
|
||||
if completed % 10 == 0 || completed == total_rows {
|
||||
print!(
|
||||
"[ {:.2} % ]\r",
|
||||
(1.0 - ((j + 1) as f64 / image_width as f64)) * 100.0
|
||||
"\r[ {:.2} % ] Rendering...",
|
||||
(completed as f64 / total_rows as f64) * 100.0
|
||||
);
|
||||
stdout().flush().expect("Can flush stdout");
|
||||
let _ = stdout().flush();
|
||||
}
|
||||
println!("Took {:.6}ms", now.elapsed().as_millis());
|
||||
println!("Took {:.6}s", now.elapsed().as_secs_f64());
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn random_f64() -> f64 {
|
||||
|
||||
// PLEASE CHANGE
|
||||
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 {
|
||||
|
||||
@@ -15,7 +15,7 @@ impl 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 a = r.direction().length_squared();
|
||||
let half_b = oc.dot(&r.direction());
|
||||
|
||||
Reference in New Issue
Block a user