M .gitignore => .gitignore +2 -0
@@ 1,1 1,3 @@
/target
+*.ppm
+tags
M Cargo.lock => Cargo.lock +78 -0
@@ 1,5 1,83 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
name = "ray_tracing_in_one_weekend"
version = "0.1.0"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
M Cargo.toml => Cargo.toml +1 -0
@@ 7,3 7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+rand = "0.8"
A src/camera.rs => src/camera.rs +36 -0
@@ 0,0 1,36 @@
+use crate::{Point3, Ray, Vec3};
+
+pub struct Camera {
+ origin: Point3,
+ lower_left_corner: Point3,
+ horizontal: Vec3,
+ vertical: Vec3,
+}
+
+impl Camera {
+ pub fn new() -> Self {
+ let aspect_ratio = 16.0 / 9.0;
+ let viewport_height = 2.0;
+ let viewport_width = aspect_ratio * viewport_height;
+ let focal_length = 1.0;
+
+ let origin = Point3::new(0., 0., 0.);
+ let horizontal = Vec3::new(viewport_width, 0.0, 0.0);
+ let vertical = Vec3::new(0.0, viewport_height, 0.0);
+ let lower_left_corner =
+ origin - horizontal / 2. - vertical / 2. - Vec3::new(0., 0., focal_length);
+ Self {
+ origin,
+ lower_left_corner,
+ horizontal,
+ vertical,
+ }
+ }
+
+ pub fn get_ray(&self, u: f64, v: f64) -> Ray {
+ return Ray::new(
+ &self.origin,
+ &(self.lower_left_corner + u * self.horizontal + v * self.vertical - self.origin),
+ );
+ }
+}
M src/hittable_list.rs => src/hittable_list.rs +1 -2
@@ 1,6 1,5 @@
use crate::hittable::*;
use crate::ray::*;
-use crate::vec3::*;
use std::sync::Arc;
#[derive(Clone)]
@@ 10,7 9,7 @@ pub struct HittableList {
impl HittableList {
pub fn empty() -> Self {
- HittableList{ objects: vec![] }
+ HittableList { objects: vec![] }
}
pub fn clear(&mut self) {
M src/main.rs => src/main.rs +17 -22
@@ 18,6 18,9 @@ use sphere::*;
mod rtweekend;
use rtweekend::*;
+mod camera;
+use camera::*;
+
fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 {
let oc = r.origin() - *center;
let a = r.direction().length_squared();
@@ 34,7 37,7 @@ fn hit_sphere(center: &Point3, radius: f64, r: &Ray) -> f64 {
fn ray_color(r: &Ray, world: &dyn Hittable) -> Color {
if let Some(rec) = world.hit(r, 0.0, INFINITY) {
- return 0.5 * (rec.normal + Color::new(1.0,1.0,1.0));
+ return 0.5 * (rec.normal + Color::new(1.0, 1.0, 1.0));
}
let unit_direction = unit_vector(r.direction());
let t = 0.5 * (unit_direction.y() + 1.0);
@@ 48,25 51,17 @@ fn main() {
// Image
let aspect_ratio = 16.0 / 9.0;
let image_width = 400;
- let image_width = 800;
+ // let image_width = 1600;
let image_height = (image_width as f64 / aspect_ratio) as i32;
+ let samples_per_pixel = 100;
// World
let mut world = HittableList::empty();
- world.add(Arc::new(Sphere::new(Point3::new(0.0,0.0,-1.0), 0.5)));
- world.add(Arc::new(Sphere::new(Point3::new(0.0,-100.5,-1.0), 100.0)));
+ world.add(Arc::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));
+ world.add(Arc::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
// Camera
-
- let viewport_height = 2.0;
- let viewport_width = aspect_ratio * viewport_height;
- let focal_length = 1.0;
-
- let origin = Point3::new(0.0, 0.0, 0.0);
- let horizontal = Vec3::new(viewport_width, 0.0, 0.0);
- let vertical = Vec3::new(0.0, viewport_height, 0.0);
- let lower_left_corner =
- origin - horizontal / 2f64 - vertical / 2f64 - Vec3::new(0.0, 0.0, focal_length);
+ let cam = Camera::new();
// Render
@@ 75,14 70,14 @@ fn main() {
for j in (0..=(image_height - 1)).rev() {
eprint!("\rScanlines remaining: {} ", j);
for i in 0..image_width {
- let u = i as f64 / (image_width - 1) as f64;
- let v = j as f64 / (image_height - 1) as f64;
- let r = Ray::new(
- &origin,
- &(lower_left_corner + u * horizontal + v * vertical - origin),
- );
- let pixel_color = ray_color(&r, &world);
- write_color(&mut handle, pixel_color);
+ 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);
+ }
+ write_color(&mut handle, pixel_color, samples_per_pixel);
}
}
eprintln!("\nDone!");
A src/rtweekend.rs => src/rtweekend.rs +16 -0
@@ 0,0 1,16 @@
+use rand::Rng;
+pub use std::f64::consts::PI;
+pub use std::f64::INFINITY;
+use std::ops::Range;
+
+pub fn degrees_to_radians(degrees: f64) -> f64 {
+ degrees * PI / 180.0
+}
+
+pub fn random_double() -> f64 {
+ random_double_range(0.0..1.0)
+}
+
+pub fn random_double_range(r: Range<f64>) -> f64 {
+ rand::thread_rng().gen_range(r)
+}
M src/vec3.rs => src/vec3.rs +14 -4
@@ 163,13 163,23 @@ pub fn unit_vector(v: Vec3) -> Vec3 {
v / v.length()
}
-pub fn write_color(out: &mut impl std::io::Write, pixel_color: Color) {
+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;
+ g *= scale;
+ b *= scale;
+
write!(
out,
"{} {} {}\n",
- (255.999 * pixel_color.x()) as i32,
- (255.999 * pixel_color.y()) as i32,
- (255.999 * pixel_color.z()) as i32
+ (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();
}