2022-05-05 13:19:56 +02:00
|
|
|
extern crate image;
|
|
|
|
|
2022-05-11 18:38:30 +02:00
|
|
|
mod camera;
|
2022-04-20 18:58:58 +02:00
|
|
|
mod color;
|
2022-04-27 18:27:07 +02:00
|
|
|
mod hittable;
|
2022-05-04 18:21:48 +02:00
|
|
|
mod hittable_list;
|
2022-04-20 18:58:58 +02:00
|
|
|
mod ray;
|
2022-05-04 18:21:48 +02:00
|
|
|
mod utility;
|
2022-05-11 18:38:30 +02:00
|
|
|
mod vec3;
|
2022-06-08 18:28:45 +02:00
|
|
|
mod material;
|
2022-05-11 18:38:30 +02:00
|
|
|
|
|
|
|
use camera::Camera;
|
|
|
|
use hittable::{HitRecord, Hittable, Sphere};
|
2022-05-04 18:21:48 +02:00
|
|
|
use hittable_list::HittableList;
|
2022-05-11 18:38:30 +02:00
|
|
|
use image::{Rgb, RgbImage};
|
2022-05-05 13:19:56 +02:00
|
|
|
use ray::Ray;
|
2022-06-01 17:59:25 +02:00
|
|
|
use rayon::prelude::*;
|
2022-06-01 20:13:55 +02:00
|
|
|
use std::env;
|
|
|
|
use std::sync::atomic::{AtomicU32, Ordering};
|
|
|
|
use std::sync::Arc;
|
|
|
|
use vec3::{Color, Point3, Vec3};
|
2022-06-08 18:28:45 +02:00
|
|
|
use material::{Material, Lambertian, Metal};
|
2022-04-20 18:58:58 +02:00
|
|
|
|
2022-05-18 17:49:46 +02:00
|
|
|
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
|
2022-05-04 18:21:48 +02:00
|
|
|
let mut rec = HitRecord::empty();
|
2022-04-20 18:59:29 +02:00
|
|
|
|
2022-05-18 17:49:46 +02:00
|
|
|
if depth <= 0 {
|
2022-06-08 18:28:45 +02:00
|
|
|
return Color::null();
|
2022-05-18 17:49:46 +02:00
|
|
|
}
|
|
|
|
|
2022-06-08 18:28:45 +02:00
|
|
|
if world.hit(r, 0.001, f64::INFINITY, &mut rec) {
|
|
|
|
let mut scattered = Ray::new(Point3::null(), Vec3::null());
|
|
|
|
let mut attenuation = Color::null();
|
|
|
|
if rec.mat_ptr.scatter(r, &rec, &mut attenuation, &mut scattered) {
|
|
|
|
return attenuation * ray_color(&scattered, world, depth-1);
|
|
|
|
}
|
|
|
|
return Color::null();
|
|
|
|
|
|
|
|
//let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
|
|
|
|
//return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
|
2022-05-04 18:21:48 +02:00
|
|
|
}
|
2022-04-20 18:58:58 +02:00
|
|
|
let unit_direction = r.direction();
|
2022-04-20 18:59:29 +02:00
|
|
|
let t = 0.5 * (unit_direction.y() + 1.0);
|
|
|
|
return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0);
|
2022-04-20 18:58:58 +02:00
|
|
|
}
|
2022-04-12 19:14:11 +02:00
|
|
|
|
2022-04-07 23:04:50 +02:00
|
|
|
fn main() {
|
2022-04-20 18:58:58 +02:00
|
|
|
// File
|
|
|
|
let mut default_file = "image.ppm";
|
|
|
|
|
|
|
|
// Image
|
|
|
|
let aspect_ratio = 16.0 / 9.0;
|
2022-06-08 18:28:45 +02:00
|
|
|
let image_width = 1920;
|
2022-05-05 13:19:56 +02:00
|
|
|
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
2022-06-04 13:51:32 +02:00
|
|
|
let samples_per_pixel = 100_u32;
|
2022-05-18 17:49:46 +02:00
|
|
|
let max_depth = 50;
|
2022-04-20 18:58:58 +02:00
|
|
|
|
2022-05-04 18:21:48 +02:00
|
|
|
// World
|
|
|
|
let mut world = HittableList::new();
|
2022-06-08 18:28:45 +02:00
|
|
|
|
|
|
|
let material_ground = Arc::new(Lambertian::new(&Color::new(0.8, 0.8, 0.0)));
|
|
|
|
let material_center = Arc::new(Lambertian::new(&Color::new(0.7, 0.1, 0.2)));
|
|
|
|
let material_left = Arc::new(Metal::new(&Color::new(0.8, 0.8, 0.8)));
|
|
|
|
let material_right = Arc::new(Metal::new(&Color::new(0.8, 0.6, 0.2)));
|
|
|
|
let material_mirror = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.9)));
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-05-18 16:58:02 +02:00
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(
|
2022-05-18 17:49:46 +02:00
|
|
|
Point3::new(0.0, -100.5, -1.0),
|
2022-05-11 18:38:30 +02:00
|
|
|
100.0,
|
2022-06-08 18:28:45 +02:00
|
|
|
material_ground.clone(),
|
2022-05-11 18:38:30 +02:00
|
|
|
)));
|
2022-05-18 16:58:02 +02:00
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(
|
2022-06-08 18:28:45 +02:00
|
|
|
Point3::new(0.0, 0.0, -1.0),
|
|
|
|
0.5,
|
|
|
|
material_center.clone(),
|
2022-05-11 18:38:30 +02:00
|
|
|
)));
|
2022-05-18 16:58:02 +02:00
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(
|
2022-06-08 18:28:45 +02:00
|
|
|
Point3::new(-1.0, 0.0, -1.0),
|
|
|
|
0.5,
|
|
|
|
material_mirror.clone(),
|
|
|
|
)));
|
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(
|
|
|
|
Point3::new(1.0, 0.0, -1.0),
|
|
|
|
0.5,
|
|
|
|
material_mirror.clone(),
|
2022-05-11 18:38:30 +02:00
|
|
|
)));
|
2022-05-18 16:58:02 +02:00
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(
|
2022-06-08 18:28:45 +02:00
|
|
|
Point3::new(-1.0, 1.1, -1.2),
|
|
|
|
0.4,
|
|
|
|
material_left.clone(),
|
2022-05-11 18:38:30 +02:00
|
|
|
)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
for i in -15..15 {
|
|
|
|
for j in -15..15 {
|
2022-06-01 20:13:55 +02:00
|
|
|
world.add(Box::<Sphere>::new(Sphere::new(Point3::new(j as f64/5.0 as f64, i as f64/5.0 as f64, -1.5), 0.08)));
|
2022-05-11 18:38:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2022-05-04 18:21:48 +02:00
|
|
|
|
2022-04-20 18:58:58 +02:00
|
|
|
// Camera
|
2022-05-11 18:38:30 +02:00
|
|
|
let cam = Camera::new();
|
2022-04-20 18:59:29 +02:00
|
|
|
|
2022-04-20 18:58:58 +02:00
|
|
|
// Render
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
if args.len() > 1 && args[1] != "" {
|
|
|
|
default_file = &args[1];
|
|
|
|
}
|
2022-05-05 13:19:56 +02:00
|
|
|
|
2022-05-05 13:33:06 +02:00
|
|
|
let mut image = RgbImage::new(image_width, image_height);
|
2022-05-05 13:19:56 +02:00
|
|
|
|
2022-06-01 20:13:55 +02:00
|
|
|
let atomic_counter = Arc::new(AtomicU32::new(0));
|
|
|
|
let color_lines: Vec<_> = (0..image_height)
|
|
|
|
.into_par_iter()
|
|
|
|
.rev()
|
|
|
|
.map(|j| {
|
|
|
|
let v = atomic_counter.fetch_add(1, Ordering::Relaxed);
|
|
|
|
eprint!("\rScanlines remaining: {:5}", image_height - v);
|
|
|
|
|
|
|
|
let mut colors = Vec::new();
|
|
|
|
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 + utility::random_f64()) / (image_width - 1) as f64;
|
|
|
|
let v = (j as f64 + utility::random_f64()) / (image_height - 1) as f64;
|
|
|
|
let r = cam.get_ray(u, v);
|
|
|
|
pixel_color += ray_color(&r, &world, max_depth);
|
|
|
|
}
|
|
|
|
colors.push(pixel_color);
|
2022-05-11 18:38:30 +02:00
|
|
|
}
|
2022-06-01 20:13:55 +02:00
|
|
|
return colors;
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
eprint!("\rScanlines remaining: {:5}", 0);
|
2022-04-07 23:04:50 +02:00
|
|
|
|
2022-06-01 17:59:25 +02:00
|
|
|
(0..image_height).into_iter().rev().for_each(|j| {
|
|
|
|
(0..image_width).into_iter().for_each(|i| {
|
2022-05-11 18:38:30 +02:00
|
|
|
color::put_color(
|
|
|
|
&mut image,
|
2022-06-01 17:59:25 +02:00
|
|
|
&color_lines[(image_height - j - 1) as usize][i as usize],
|
2022-05-11 18:38:30 +02:00
|
|
|
i,
|
|
|
|
image_height - j - 1,
|
|
|
|
samples_per_pixel,
|
|
|
|
);
|
2022-06-01 17:59:25 +02:00
|
|
|
})
|
|
|
|
});
|
|
|
|
|
2022-05-18 16:58:08 +02:00
|
|
|
image.save(default_file).unwrap();
|
|
|
|
eprintln!("\nDone!");
|
|
|
|
}
|