Compare commits
2 Commits
388c48d236
...
4b8b556ea3
Author | SHA1 | Date | |
---|---|---|---|
4b8b556ea3 | |||
2903c9b0b9 |
122
Cargo.lock
generated
122
Cargo.lock
generated
@ -2,12 +2,69 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"memoffset",
|
||||||
|
"once_cell",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -19,12 +76,46 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.126"
|
version = "0.2.126"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -61,13 +152,44 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"crossbeam-deque",
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustracer"
|
name = "rustracer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
rayon = "1.5.3"
|
87
src/main.rs
87
src/main.rs
@ -1,8 +1,13 @@
|
|||||||
|
use std::sync::Mutex;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::camera::Camera;
|
use crate::camera::Camera;
|
||||||
use crate::hittable::{Hittable, Sphere};
|
use crate::hittable::{Hittable, Sphere};
|
||||||
|
use crate::output::{Output, P3};
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::vec3::{Color, Point3, Vec3};
|
use crate::vec3::{Color, Point3, Vec3};
|
||||||
use rand::distributions::{Distribution, Uniform};
|
use rand::distributions::{Distribution, Uniform};
|
||||||
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use crate::material::{Dielectric, Lambertian, Material, Metal};
|
use crate::material::{Dielectric, Lambertian, Material, Metal};
|
||||||
|
|
||||||
mod vec3;
|
mod vec3;
|
||||||
@ -10,9 +15,10 @@ mod ray;
|
|||||||
mod hittable;
|
mod hittable;
|
||||||
mod material;
|
mod material;
|
||||||
mod camera;
|
mod camera;
|
||||||
|
mod output;
|
||||||
|
|
||||||
fn random_scene() -> Vec<Box<dyn Hittable>> {
|
fn random_scene() -> Vec<Box<dyn Hittable + Sync>> {
|
||||||
let mut world:Vec<Box<dyn Hittable>> = Vec::new();
|
let mut world:Vec<Box<dyn Hittable + Sync>> = Vec::new();
|
||||||
|
|
||||||
let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
|
let material_ground = Material::Lambertian(Lambertian::new(Color::new(0.5, 0.5, 0.5)));
|
||||||
let ground = Sphere {
|
let ground = Sphere {
|
||||||
@ -52,16 +58,37 @@ fn random_scene() -> Vec<Box<dyn Hittable>> {
|
|||||||
world.push(sphere);
|
world.push(sphere);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let material1 = Material::Dielectric(Dielectric::new(1.5));
|
||||||
|
world.push(Box::new(Sphere {
|
||||||
|
center: Point3::new(0.0, 1.0, 0.0),
|
||||||
|
radius: 1.0,
|
||||||
|
material: material1
|
||||||
|
}));
|
||||||
|
let material2 = Material::Lambertian(Lambertian::new(Color::new(0.4, 0.2, 0.1)));
|
||||||
|
world.push(Box::new(Sphere {
|
||||||
|
center: Point3::new(-4.0, 1.0, 0.0),
|
||||||
|
radius: 1.0,
|
||||||
|
material: material2
|
||||||
|
}));
|
||||||
|
let material3 = Material::Metal(Metal::new(Color::new(0.7, 0.6, 0.5), 0.0));
|
||||||
|
world.push(Box::new(Sphere {
|
||||||
|
center: Point3::new(4.0, 1.0, 0.0),
|
||||||
|
radius: 1.0,
|
||||||
|
material: material3
|
||||||
|
}));
|
||||||
|
|
||||||
world
|
world
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Image
|
// Image
|
||||||
const ASPECT_RATIO: f64 = 3.0 / 2.0;
|
const ASPECT_RATIO: f64 = 3.0 / 2.0;
|
||||||
const IMAGE_WIDTH: i32 = 1200;
|
const IMAGE_WIDTH: usize = 1200;
|
||||||
const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32;
|
const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize;
|
||||||
const SAMPLES_PER_PIXEL: i32 = 10;
|
const SAMPLES_PER_PIXEL: i32 = 500;
|
||||||
const MAX_DEPTH: i32 = 50;
|
const MAX_DEPTH: i32 = 50;
|
||||||
|
let hh = IMAGE_HEIGHT;
|
||||||
|
|
||||||
let look_from = Point3::new(13.0, 2.0, 3.0);
|
let look_from = Point3::new(13.0, 2.0, 3.0);
|
||||||
let look_at = Point3::new(0.0, 0.0, 0.0);
|
let look_at = Point3::new(0.0, 0.0, 0.0);
|
||||||
@ -79,26 +106,38 @@ fn main() {
|
|||||||
// World
|
// World
|
||||||
let world= random_scene();
|
let world= random_scene();
|
||||||
|
|
||||||
println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT);
|
|
||||||
|
|
||||||
let between = Uniform::from(0.0..1.0);
|
let between = Uniform::from(0.0..1.0);
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
for j in (0..IMAGE_HEIGHT).rev() {
|
let start = Instant::now();
|
||||||
eprint!("\rScanlines remaining: {} ", j);
|
let mut pixels = vec![0; IMAGE_WIDTH * IMAGE_HEIGHT * 3];
|
||||||
for i in 0..IMAGE_WIDTH {
|
let bands: Vec<(usize, &mut [u8])> = pixels.chunks_mut(3).enumerate().collect();
|
||||||
let mut color = Color::default();
|
let count = Mutex::new(0);
|
||||||
for s in 0..SAMPLES_PER_PIXEL {
|
bands.into_par_iter().for_each(|(i, pixel)| {
|
||||||
let random_number = between.sample(&mut rng);
|
let row = IMAGE_HEIGHT - (i / IMAGE_WIDTH) - 1;
|
||||||
let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
|
let col = i % IMAGE_WIDTH;
|
||||||
let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
|
let mut rng = rand::thread_rng();
|
||||||
let ray = cam.get_ray(u, v);
|
let mut color = Color::default();
|
||||||
if i == 200 && (j == 112 || j == 113) {
|
(0..SAMPLES_PER_PIXEL).for_each(|_s| {
|
||||||
let tt = 0;
|
let random_number = between.sample(&mut rng);
|
||||||
}
|
let u = (col as f64 + random_number) / (IMAGE_WIDTH - 1) as f64;
|
||||||
color += ray.pixel_color(&world, MAX_DEPTH);
|
let v = (row as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64;
|
||||||
|
let ray = cam.get_ray(u, v);
|
||||||
|
color += ray.pixel_color(&world, MAX_DEPTH);
|
||||||
|
});
|
||||||
|
let bytes = color.into_bytes(SAMPLES_PER_PIXEL);
|
||||||
|
pixel[0] = bytes[0];
|
||||||
|
pixel[1] = bytes[1];
|
||||||
|
pixel[2] = bytes[2];
|
||||||
|
if i % 100 == 0 {
|
||||||
|
let mut rem = count.lock().unwrap();
|
||||||
|
let percent_done_before = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT);
|
||||||
|
*rem += 100;
|
||||||
|
let percent_done_after = 100 * *rem / (IMAGE_WIDTH * IMAGE_HEIGHT);
|
||||||
|
if percent_done_before != percent_done_after {
|
||||||
|
eprint!("\rProgress: {}% ", percent_done_after);
|
||||||
}
|
}
|
||||||
color.write_color(SAMPLES_PER_PIXEL);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
eprintln!("\nDone");
|
P3::write("imc.ppm", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}");
|
||||||
|
eprintln!("\nDone. Time: {}ms", start.elapsed().as_millis());
|
||||||
}
|
}
|
||||||
|
19
src/output.rs
Normal file
19
src/output.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use std::{fs::File, io::{Error, Write}};
|
||||||
|
|
||||||
|
pub trait Output {
|
||||||
|
fn write(filename: &str, pixels: &Vec<u8>, width: usize, height: usize) -> Result<File, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct P3 {}
|
||||||
|
impl Output for P3 {
|
||||||
|
fn write(filename: &str, pixels: &Vec<u8>, width: usize, height: usize) -> Result<File, Error> {
|
||||||
|
let mut file = File::create(filename)?;
|
||||||
|
file.write(format!("P3\n{} {}\n255\n", width, height).as_bytes())?;
|
||||||
|
let lines: Result<Vec<usize>, Error> = pixels
|
||||||
|
.chunks(3)
|
||||||
|
.map(|chunk| format!("{} {} {}\n", chunk[0], chunk[1], chunk[2]))
|
||||||
|
.map(|line| file.write(line.as_bytes()))
|
||||||
|
.collect();
|
||||||
|
lines.map(|_v| file)
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@ impl Ray {
|
|||||||
}
|
}
|
||||||
pub fn direction(&self) -> Vec3 { self.direction }
|
pub fn direction(&self) -> Vec3 { self.direction }
|
||||||
pub fn origin(&self) -> Point3 { self.origin }
|
pub fn origin(&self) -> Point3 { self.origin }
|
||||||
pub fn pixel_color(&self, world: &Vec<Box<dyn Hittable>>, depth: i32) -> Color {
|
pub fn pixel_color(&self, world: &Vec<Box<dyn Hittable + Sync>>, depth: i32) -> Color {
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
return Color::default();
|
return Color::default();
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ impl Ray {
|
|||||||
}
|
}
|
||||||
fn hit_world<'material>(
|
fn hit_world<'material>(
|
||||||
&self,
|
&self,
|
||||||
world: &'material Vec<Box<dyn Hittable>>,
|
world: &'material Vec<Box<dyn Hittable + Sync>>,
|
||||||
t_min: f64,
|
t_min: f64,
|
||||||
t_max: f64,
|
t_max: f64,
|
||||||
) -> Option<HitRecord<'material>> {
|
) -> Option<HitRecord<'material>> {
|
||||||
|
12
src/vec3.rs
12
src/vec3.rs
@ -105,12 +105,12 @@ fn test_refract() {
|
|||||||
let n = Point3::new(-1.0, 0.0, 0.0);
|
let n = Point3::new(-1.0, 0.0, 0.0);
|
||||||
let etai_over_etat = 1.0;
|
let etai_over_etat = 1.0;
|
||||||
let expected = Point3::new(0.0, 1.0, 0.0);
|
let expected = Point3::new(0.0, 1.0, 0.0);
|
||||||
let actual = uv.refract_orig( &n, etai_over_etat);
|
let actual = uv.refract( &n, etai_over_etat);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
pub fn write_color(self: Color, samples_per_pixel: i32) {
|
fn tone_map(self: &Color, samples_per_pixel: i32) -> (f64, f64, f64) {
|
||||||
let scale = 1.0 / samples_per_pixel as f64;
|
let scale = 1.0 / samples_per_pixel as f64;
|
||||||
let r = f64::sqrt(scale * self.x);
|
let r = f64::sqrt(scale * self.x);
|
||||||
let g = f64::sqrt(scale * self.y);
|
let g = f64::sqrt(scale * self.y);
|
||||||
@ -118,8 +118,16 @@ impl Color {
|
|||||||
let r = 256.0 * f64::clamp(r, 0.0, 0.999);
|
let r = 256.0 * f64::clamp(r, 0.0, 0.999);
|
||||||
let g = 256.0 * f64::clamp(g, 0.0, 0.999);
|
let g = 256.0 * f64::clamp(g, 0.0, 0.999);
|
||||||
let b = 256.0 * f64::clamp(b, 0.0, 0.999);
|
let b = 256.0 * f64::clamp(b, 0.0, 0.999);
|
||||||
|
(r, g, b)
|
||||||
|
}
|
||||||
|
pub fn write_color(self: &Color, samples_per_pixel: i32) {
|
||||||
|
let (r, g, b) = self.tone_map(samples_per_pixel);
|
||||||
println!("{} {} {}", r as i32, g as i32, b as i32);
|
println!("{} {} {}", r as i32, g as i32, b as i32);
|
||||||
}
|
}
|
||||||
|
pub fn into_bytes(self: &Color, samples_per_pixel: i32) -> Vec<u8> {
|
||||||
|
let (r, g, b) = self.tone_map(samples_per_pixel);
|
||||||
|
vec![r as u8, g as u8, b as u8]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Vec3 {
|
impl Default for Vec3 {
|
||||||
|
Loading…
Reference in New Issue
Block a user